diff --git a/tasmota/settings.h b/tasmota/settings.h index 07792022a..c13faaf42 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -309,21 +309,20 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t mirror : 1; uint32_t flip : 1; uint32_t rtsp : 1; - uint32_t spare4 : 1; - uint32_t spare5 : 1; - uint32_t spare6 : 1; - uint32_t spare7 : 1; - uint32_t spare8 : 1; - uint32_t spare9 : 1; - uint32_t spare10 : 1; - uint32_t spare11 : 1; - uint32_t spare12 : 1; - uint32_t spare13 : 1; - uint32_t spare14 : 1; + uint32_t awb : 1; + uint32_t awb_gain : 1; + uint32_t aec : 1; + uint32_t aec2 : 1; + uint32_t agc : 1; + uint32_t raw_gma : 1; + uint32_t lenc : 1; + uint32_t colorbar : 1; + uint32_t wpc : 1; + uint32_t dcw : 1; + uint32_t bpc : 1; uint32_t spare15 : 1; uint32_t spare16 : 1; - uint32_t spare17 : 1; - uint32_t spare18 : 1; + uint32_t feature : 2; uint32_t contrast : 3; uint32_t brightness : 3; uint32_t saturation : 3; @@ -331,6 +330,22 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu }; } WebCamCfg; +typedef union { + uint32_t data; + struct { + uint32_t wb_mode : 3; + uint32_t ae_level : 3; + uint32_t aec_value : 11; + uint32_t gainceiling : 3; + uint32_t agc_gain: 5; + uint32_t special_effect : 3; + uint32_t spare28 : 1; + uint32_t spare29 : 1; + uint32_t spare30 : 1; + uint32_t upgraded : 1; + }; +} WebCamCfg2; + typedef union { uint16_t data; struct { @@ -572,7 +587,7 @@ typedef struct { uint8_t eth_type; // 446 uint8_t eth_clk_mode; // 447 - uint8_t free_esp32_448[4]; // 448 + WebCamCfg2 webcam_config2; // 448 #ifdef CONFIG_IDF_TARGET_ESP32S2 uint8_t free_esp32s2_456[2]; // 456 - fix 32-bit offset for WebCamCfg #endif diff --git a/tasmota/xdrv_81_esp32_webcam.ino b/tasmota/xdrv_81_esp32_webcam.ino index d16ff04e0..b00c3504d 100644 --- a/tasmota/xdrv_81_esp32_webcam.ino +++ b/tasmota/xdrv_81_esp32_webcam.ino @@ -59,8 +59,36 @@ * WcSaturation = Set picture Saturation -2 ... +2 * WcBrightness = Set picture Brightness -2 ... +2 * WcContrast = Set picture Contrast -2 ... +2 - * WcInit = Init Camera Interface - * WcRtsp = Control RTSP Server, 0=disable, 1=enable (forces restart) (if defined ENABLE_RTSPSERVER) + * WcSpecialEffekt = Set Special Picture Effect: 0 = off, 1 = , 2 = , 3 = , 4 = , 5 = , 6 = + * WcAWB = Auto White Balance, 0 = no, 1 = yes + * WcWBMode = White Balance Mode, 0 = auto, 1 = + * WcAWBGain = Auto White Balance Gain, 0 = no, 1 = yes + * WcAEC = Auto exposure control (Sensor), 0 = no, 1 = yes + * WcAECDSP = Auto exposure control (DSP), 0 = no, 1 = yes + * WcAECValue = Auto exposure control value, 0 ... 1024 + * WcAECLevel = Auto exposure control level, -2 ... +2 + * WcAGC = Auto gain control, 0 = no, 1 = yes + * WcAGCGain = Auto gain control gain, 0 .. 30 + * WcGainCeiling = Gain ceiling, 0 .. 6 (0 = x2, 1 = x4, 2 = x8, 3 = x16, 4 = x32, 5 = x64, 6 = x128) + * WcGammaCorrect = Auto Gamma Correct, 0 = no, 1 = yes + * WcLensCorrect = Auto Lens Correct, 0 = no, 1 = yes + * WcWPC = White Pixel Correct, 0 = no, 1 = yes + * WcDCW = Downscale, 0 = no, 1 = yes + * WcBPC = Black Pixel Correct, 0 = no, 1 = yes + * WcColorbar = Show Colorbar, 0 = no, 1 = yes + * WcFeature = Set extended Feature, 0 = off, 1 = reduce FPS, 2 = Nightmode + * WcStats = Show Statistics + * WcInit = Init Camera Interface + * WcRtsp = Control RTSP Server, 0=disable, 1=enable (forces restart) (if defined ENABLE_RTSPSERVER) + * + * WcFeature Explanation + * See https://hobbylad.files.wordpress.com/2020/02/ov2640-camera-module-software-application-notes.pdf + * for more Information + * 0: Normal Operation + * 1: Reduced FPS: Set XCLK Divisor to 2. Reduces Framerate and also increases exposure time. This causes + * better low light performance. See above document, page 6 + * 2: Night Mode: Further increase exposure time and lower the Framerate depending on available light. + * See above Document, Page 8 * * Only boards with PSRAM should be used. To enable PSRAM board should be se set to esp32cam in common32 of platform_override.ini * board = esp32cam @@ -163,6 +191,15 @@ struct { #endif // ENABLE_RTSPSERVER } Wc; +struct { + uint32_t camcnt = 0; + uint32_t camfps = 0; + uint32_t camfail = 0; + uint32_t jpegfail = 0; + uint32_t clientfail = 0; + char name[7] = "Webcam"; +} WcStats; + /*********************************************************************************************/ void WcInterrupt(uint32_t state) { @@ -198,6 +235,115 @@ bool WcPinUsed(void) { return pin_used; } +void WcFeature(int32_t value) { + sensor_t * wc_s = esp_camera_sensor_get(); + if (!wc_s) { return; } + + if (value != 1) { + // CLKRC: Set Clock Divider to 0 = fullspeed + wc_s->set_reg(wc_s, 0x111, 0x3f, 0x00); + vTaskDelay(200 / portTICK_PERIOD_MS); + } + if (value != 2) { + // Stop Nightmode + wc_s->set_reg(wc_s, 0x103, 0xff, 0x0a); // COM1: Reset dummy frames + wc_s->set_reg(wc_s, 0x10f, 0xff, 0x43); // Reserved Reg + wc_s->set_reg(wc_s, 0x10f, 0xff, 0x4b); // Reserved Reg + vTaskDelay(1000 / portTICK_PERIOD_MS); + wc_s->set_reg(wc_s, 0x10f, 0xff, 0x43); // Reserved Reg + } + + switch(value) { + case 1: + // Reduce FPS + // CLKRC: Set Clock Divider to 2 + wc_s->set_reg(wc_s, 0x111, 0x3f, 0x02); + break; + case 2: + // Start Nightmode + wc_s->set_reg(wc_s, 0x10f, 0xff, 0x4b); // Reserved Reg + wc_s->set_reg(wc_s, 0x103, 0xff, 0xcf); // COM1: Allow 7 dummy frames + break; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Feature: %d"), value); +} + +void WcApplySettings() { + sensor_t * wc_s = esp_camera_sensor_get(); + if (!wc_s) { return; } + + wc_s->set_vflip(wc_s, Settings->webcam_config.flip); + wc_s->set_hmirror(wc_s, Settings->webcam_config.mirror); + + wc_s->set_brightness(wc_s, Settings->webcam_config.brightness - 2); + wc_s->set_saturation(wc_s, Settings->webcam_config.saturation - 2); + wc_s->set_contrast(wc_s, Settings->webcam_config.contrast - 2); + + wc_s->set_special_effect(wc_s, Settings->webcam_config2.special_effect); + + wc_s->set_whitebal(wc_s, Settings->webcam_config.awb); + wc_s->set_wb_mode(wc_s, Settings->webcam_config2.wb_mode); + wc_s->set_awb_gain(wc_s, Settings->webcam_config.awb_gain); + + wc_s->set_exposure_ctrl(wc_s, Settings->webcam_config.aec); + wc_s->set_aec_value(wc_s, Settings->webcam_config2.aec_value - 2); + wc_s->set_ae_level(wc_s, Settings->webcam_config2.ae_level); + wc_s->set_aec2(wc_s, Settings->webcam_config.aec2); + + wc_s->set_gain_ctrl(wc_s, Settings->webcam_config.agc); + wc_s->set_agc_gain(wc_s, Settings->webcam_config2.agc_gain); + wc_s->set_gainceiling(wc_s, (gainceiling_t)Settings->webcam_config2.gainceiling); + + wc_s->set_raw_gma(wc_s, Settings->webcam_config.raw_gma); + wc_s->set_lenc(wc_s, Settings->webcam_config.lenc); + wc_s->set_wpc(wc_s, Settings->webcam_config.wpc); + wc_s->set_dcw(wc_s, Settings->webcam_config.dcw); + wc_s->set_bpc(wc_s, Settings->webcam_config.bpc); + + WcFeature(Settings->webcam_config.feature); + + AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Settings updated")); +} + +void WcSetDefaults(uint32_t upgrade) { + if (!upgrade) { + Settings->webcam_config.flip = 0; + Settings->webcam_config.mirror = 0; + + Settings->webcam_config.saturation = 2; // = 0 + Settings->webcam_config.brightness = 2; // = 0 + Settings->webcam_config.contrast = 2; // = 0 + } + + Settings->webcam_config2.special_effect = 0; + Settings->webcam_config.colorbar = 0; + + Settings->webcam_config.awb = 1; // white balance + Settings->webcam_config2.wb_mode = 0; // white balance mode + Settings->webcam_config.awb_gain = 1; // white blance gain + + Settings->webcam_config.aec = 1; // autoexposure (sensor) + Settings->webcam_config.aec2 = 1; // autoexposure (dsp) + Settings->webcam_config2.ae_level = 2; // autoexposure level (-2 - +2, default 0) + Settings->webcam_config2.aec_value = 204; // manual exposure value + + Settings->webcam_config.agc = 1; // auto gain control + Settings->webcam_config2.agc_gain = 5; // manual gain control + Settings->webcam_config2.gainceiling = 0; // auto gain ceiling + + Settings->webcam_config.raw_gma = 1; // gamma correct + Settings->webcam_config.lenc = 1; // lens correction + Settings->webcam_config.wpc = 1; // white pixel correct + Settings->webcam_config.dcw = 1; // downsize en + Settings->webcam_config.bpc = 0; // black pixel correct? + + Settings->webcam_config.feature = 0; + + AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Defaults set")); + + if (Wc.up) { WcApplySettings(); } +} + uint32_t WcSetup(int32_t fsiz) { if (fsiz >= FRAMESIZE_FHD) { fsiz = FRAMESIZE_FHD - 1; } @@ -308,13 +454,6 @@ uint32_t WcSetup(int32_t fsiz) { // AddLog(LOG_LEVEL_INFO, PSTR("CAM: heap check 2: %d"),ESP_getFreeHeap()); sensor_t * wc_s = esp_camera_sensor_get(); - - wc_s->set_vflip(wc_s, Settings->webcam_config.flip); - wc_s->set_hmirror(wc_s, Settings->webcam_config.mirror); - wc_s->set_brightness(wc_s, Settings->webcam_config.brightness -2); // up the brightness just a bit - wc_s->set_saturation(wc_s, Settings->webcam_config.saturation -2); // lower the saturation - wc_s->set_contrast(wc_s, Settings->webcam_config.contrast -2); // keep contrast - // drop down frame size for higher initial frame rate wc_s->set_framesize(wc_s, (framesize_t)fsiz); @@ -327,6 +466,8 @@ uint32_t WcSetup(int32_t fsiz) { Wc.height = wc_fb->height; esp_camera_fb_return(wc_fb); + WcApplySettings(); + #ifdef USE_FACE_DETECT fd_init(); #endif @@ -350,6 +491,9 @@ int32_t WcSetOptions(uint32_t sel, int32_t value) { case 0: if (value >= 0) { s->set_framesize(s, (framesize_t)value); } res = s->status.framesize; + + // WcFeature is lost on resolution change + WcApplySettings(); break; case 1: if (value >= 0) { s->set_special_effect(s, value); } @@ -375,6 +519,74 @@ int32_t WcSetOptions(uint32_t sel, int32_t value) { if (value >= -4) { s->set_saturation(s,value); } res = s->status.saturation; break; + case 7: + if (value >= 0) { s->set_whitebal(s, value); } + res = s->status.awb; + break; + case 8: + if (value >= 0) { s->set_wb_mode(s, value); } + res = s->status.wb_mode; + break; + case 9: + if (value >= 0) { s->set_awb_gain(s, value); } + res = s->status.awb_gain; + break; + case 10: + if (value >= 0) { s->set_exposure_ctrl(s, value); } + res = s->status.aec; + break; + case 11: + if (value >= 0) { s->set_aec_value(s, value); } + res = s->status.aec_value; + break; + case 12: + if (value >= 0) { s->set_ae_level(s, value); } + res = s->status.ae_level; + break; + case 13: + if (value >= 0) { s->set_aec2(s, value); } + res = s->status.aec2; + break; + case 14: + if (value >= 0) { s->set_gain_ctrl(s, value); } + res = s->status.agc; + break; + case 15: + if (value >= 0) { s->set_agc_gain(s, value); } + res = s->status.agc_gain; + break; + case 16: + if (value >= 0) { s->set_gainceiling(s, (gainceiling_t)value); } + res = s->status.gainceiling; + break; + case 17: + if (value >= 0) { s->set_raw_gma(s, value); } + res = s->status.raw_gma; + break; + case 18: + if (value >= 0) { s->set_lenc(s, value); } + res = s->status.lenc; + break; + case 19: + if (value >= 0) { s->set_wpc(s, value); } + res = s->status.wpc; + break; + case 20: + if (value >= 0) { s->set_dcw(s, value); } + res = s->status.dcw; + break; + case 21: + // blackpixelcontrol + if (value >= 0) { s->set_bpc(s, value); } + res = s->status.bpc; + break; + case 22: + if (value >= 0) { s->set_colorbar(s, value); } + res = s->status.colorbar; + break; + case 23: + if (value >= 0) { WcFeature(value); } + break; } return res; @@ -786,6 +998,7 @@ void HandleWebcamMjpegTask(void) { if (!Wc.client.connected()) { AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Client fail")); Wc.stream_active = 0; + WcStats.clientfail++; } if (1 == Wc.stream_active) { Wc.client.flush(); @@ -801,7 +1014,9 @@ void HandleWebcamMjpegTask(void) { if (!wc_fb) { AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Frame fail")); Wc.stream_active = 0; + WcStats.camfail++; } + WcStats.camcnt++; } if (2 == Wc.stream_active) { if (wc_fb->format != PIXFORMAT_JPEG) { @@ -810,6 +1025,7 @@ void HandleWebcamMjpegTask(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: JPEG compression failed")); _jpg_buf_len = wc_fb->len; _jpg_buf = wc_fb->buf; + WcStats.jpegfail++; } } else { _jpg_buf_len = wc_fb->len; @@ -973,11 +1189,14 @@ void WcInit(void) { if (!Settings->webcam_config.data) { Settings->webcam_config.stream = 1; Settings->webcam_config.resolution = FRAMESIZE_QVGA; - Settings->webcam_config.flip = 0; - Settings->webcam_config.mirror = 0; - Settings->webcam_config.saturation = 0; // -2 - Settings->webcam_config.brightness = 3; // 1 - Settings->webcam_config.contrast = 2; // 0 + WcSetDefaults(0); + } + // previous webcam driver had only a small subset of possible config vars + // in this case we have to only set the new variables to default values + if(!Settings->webcam_config2.upgraded) { + AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Upgrade settings")); + WcSetDefaults(1); + Settings->webcam_config2.upgraded = 1; } } @@ -993,12 +1212,45 @@ void WcInit(void) { #define D_CMND_WC_SATURATION "Saturation" #define D_CMND_WC_BRIGHTNESS "Brightness" #define D_CMND_WC_CONTRAST "Contrast" +#define D_CMND_WC_SPECIALEFFECT "SpecialEffect" + +#define D_CMND_WC_AWB "AWB" +#define D_CMND_WC_WB_MODE "WBMode" +#define D_CMND_WC_AWB_GAIN "AWBGain" + +#define D_CMND_WC_AEC "AEC" +#define D_CMND_WC_AEC_VALUE "AECValue" +#define D_CMND_WC_AE_LEVEL "AELevel" +#define D_CMND_WC_AEC2 "AECDSP" + +#define D_CMND_WC_AGC "AGC" +#define D_CMND_WC_AGC_GAIN "AGCGain" +#define D_CMND_WC_GAINCEILING "GainCeiling" + +#define D_CMND_WC_RAW_GMA "GammaCorrect" +#define D_CMND_WC_LENC "LensCorrect" + +#define D_CMND_WC_WPC "WPC" +#define D_CMND_WC_DCW "DCW" +#define D_CMND_WC_BPC "BPC" + +#define D_CMND_WC_COLORBAR "Colorbar" + +#define D_CMND_WC_FEATURE "Feature" +#define D_CMND_WC_SETDEFAULTS "SetDefaults" +#define D_CMND_WC_STATS "Stats" + #define D_CMND_WC_INIT "Init" #define D_CMND_RTSP "Rtsp" const char kWCCommands[] PROGMEM = D_PRFX_WEBCAM "|" // Prefix "|" D_CMND_WC_STREAM "|" D_CMND_WC_RESOLUTION "|" D_CMND_WC_MIRROR "|" D_CMND_WC_FLIP "|" - D_CMND_WC_SATURATION "|" D_CMND_WC_BRIGHTNESS "|" D_CMND_WC_CONTRAST "|" D_CMND_WC_INIT + D_CMND_WC_SATURATION "|" D_CMND_WC_BRIGHTNESS "|" D_CMND_WC_CONTRAST "|" D_CMND_WC_SPECIALEFFECT "|" + D_CMND_WC_AWB "|" D_CMND_WC_WB_MODE "|" D_CMND_WC_AWB_GAIN "|" D_CMND_WC_AEC "|" + D_CMND_WC_AEC_VALUE "|" D_CMND_WC_AE_LEVEL "|" D_CMND_WC_AEC2 "|" D_CMND_WC_AGC "|" + D_CMND_WC_AGC_GAIN "|" D_CMND_WC_GAINCEILING "|" D_CMND_WC_RAW_GMA "|" D_CMND_WC_LENC "|" + D_CMND_WC_WPC "|" D_CMND_WC_DCW "|" D_CMND_WC_BPC "|" D_CMND_WC_COLORBAR "|" D_CMND_WC_FEATURE "|" + D_CMND_WC_SETDEFAULTS "|" D_CMND_WC_STATS "|" D_CMND_WC_INIT #ifdef ENABLE_RTSPSERVER "|" D_CMND_RTSP #endif // ENABLE_RTSPSERVER @@ -1006,7 +1258,12 @@ const char kWCCommands[] PROGMEM = D_PRFX_WEBCAM "|" // Prefix void (* const WCCommand[])(void) PROGMEM = { &CmndWebcam, &CmndWebcamStream, &CmndWebcamResolution, &CmndWebcamMirror, &CmndWebcamFlip, - &CmndWebcamSaturation, &CmndWebcamBrightness, &CmndWebcamContrast, &CmndWebcamInit + &CmndWebcamSaturation, &CmndWebcamBrightness, &CmndWebcamContrast, &CmndWebcamSpecialEffect, + &CmndWebcamAWB, &CmndWebcamWBMode, &CmndWebcamAWBGain, &CmndWebcamAEC, &CmndWebcamAECValue, + &CmndWebcamAELevel, &CmndWebcamAEC2, &CmndWebcamAGC, &CmndWebcamAGCGain, &CmndWebcamGainCeiling, + &CmndWebcamGammaCorrect, &CmndWebcamLensCorrect, &CmndWebcamWPC, &CmndWebcamDCW, &CmndWebcamBPC, + &CmndWebcamColorbar, &CmndWebcamFeature, &CmndWebcamSetDefaults, + &CmndWebcamStats, &CmndWebcamInit #ifdef ENABLE_RTSPSERVER , &CmndWebRtsp #endif // ENABLE_RTSPSERVER @@ -1015,14 +1272,26 @@ void (* const WCCommand[])(void) PROGMEM = { void CmndWebcam(void) { Response_P(PSTR("{\"" D_PRFX_WEBCAM "\":{\"" D_CMND_WC_STREAM "\":%d,\"" D_CMND_WC_RESOLUTION "\":%d,\"" D_CMND_WC_MIRROR "\":%d,\"" D_CMND_WC_FLIP "\":%d,\"" - D_CMND_WC_SATURATION "\":%d,\"" D_CMND_WC_BRIGHTNESS "\":%d,\"" D_CMND_WC_CONTRAST "\":%d" + D_CMND_WC_SATURATION "\":%d,\"" D_CMND_WC_BRIGHTNESS "\":%d,\"" D_CMND_WC_CONTRAST "\":%d,\"" + D_CMND_WC_SPECIALEFFECT "\":%d,\"" D_CMND_WC_AWB "\":%d,\"" D_CMND_WC_WB_MODE "\":%d,\"" + D_CMND_WC_AWB_GAIN "\":%d,\"" D_CMND_WC_AEC "\":%d,\"" D_CMND_WC_AEC_VALUE "\":%d,\"" + D_CMND_WC_AE_LEVEL "\":%d,\"" D_CMND_WC_AEC2 "\":%d,\"" D_CMND_WC_AGC "\":%d,\"" + D_CMND_WC_AGC_GAIN "\":%d,\"" D_CMND_WC_GAINCEILING "\":%d,\"" D_CMND_WC_RAW_GMA "\":%d,\"" + D_CMND_WC_LENC "\":%d,\"" D_CMND_WC_WPC "\":%d,\"" D_CMND_WC_DCW "\":%d,\"" D_CMND_WC_BPC "\":%d,\"" + D_CMND_WC_COLORBAR "\":%d,\"" D_CMND_WC_FEATURE "\":%d" #ifdef ENABLE_RTSPSERVER ",\"" D_CMND_RTSP "\":%d" #endif // ENABLE_RTSPSERVER "}}"), Settings->webcam_config.stream, Settings->webcam_config.resolution, Settings->webcam_config.mirror, Settings->webcam_config.flip, - Settings->webcam_config.saturation -2, Settings->webcam_config.brightness -2, Settings->webcam_config.contrast -2 + Settings->webcam_config.saturation -2, Settings->webcam_config.brightness -2, Settings->webcam_config.contrast -2, + Settings->webcam_config2.special_effect, Settings->webcam_config.awb, Settings->webcam_config2.wb_mode, + Settings->webcam_config.awb_gain, Settings->webcam_config.aec, Settings->webcam_config2.aec_value, + Settings->webcam_config2.ae_level -2, Settings->webcam_config.aec2, Settings->webcam_config.agc, + Settings->webcam_config2.agc_gain, Settings->webcam_config2.gainceiling, Settings->webcam_config.raw_gma, + Settings->webcam_config.lenc, Settings->webcam_config.wpc, Settings->webcam_config.dcw, Settings->webcam_config.bpc, + Settings->webcam_config.colorbar, Settings->webcam_config.feature #ifdef ENABLE_RTSPSERVER , Settings->webcam_config.rtsp #endif // ENABLE_RTSPSERVER @@ -1085,11 +1354,173 @@ void CmndWebcamContrast(void) { ResponseCmndNumber(Settings->webcam_config.contrast -2); } +void CmndWebcamSpecialEffect(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) { + Settings->webcam_config2.special_effect = XdrvMailbox.payload; + WcSetOptions(1, Settings->webcam_config2.special_effect); + } + ResponseCmndNumber(Settings->webcam_config2.special_effect); +} + +void CmndWebcamAWB(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.awb = XdrvMailbox.payload; + WcSetOptions(7, Settings->webcam_config.awb); + } + ResponseCmndStateText(Settings->webcam_config.awb); +} + +void CmndWebcamWBMode(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 4)) { + Settings->webcam_config2.wb_mode = XdrvMailbox.payload; + WcSetOptions(8, Settings->webcam_config2.wb_mode); + } + ResponseCmndNumber(Settings->webcam_config2.wb_mode); +} + +void CmndWebcamAWBGain(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.awb_gain = XdrvMailbox.payload; + WcSetOptions(9, Settings->webcam_config.awb_gain); + } + ResponseCmndStateText(Settings->webcam_config.awb_gain); +} + +void CmndWebcamAEC(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.aec = XdrvMailbox.payload; + WcSetOptions(10, Settings->webcam_config.aec); + } + ResponseCmndStateText(Settings->webcam_config.aec); +} + +void CmndWebcamAECValue(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1200)) { + Settings->webcam_config2.aec_value = XdrvMailbox.payload; + WcSetOptions(11, Settings->webcam_config2.aec_value); + } + ResponseCmndNumber(Settings->webcam_config2.aec_value); +} + +void CmndWebcamAELevel(void) { + if ((XdrvMailbox.payload >= -2) && (XdrvMailbox.payload <= 2)) { + Settings->webcam_config2.ae_level = XdrvMailbox.payload + 2; + WcSetOptions(12, Settings->webcam_config2.ae_level - 2); + } + ResponseCmndNumber(Settings->webcam_config2.ae_level - 2); +} + +void CmndWebcamAEC2(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.aec2 = XdrvMailbox.payload; + WcSetOptions(13, Settings->webcam_config.aec2); + } + ResponseCmndStateText(Settings->webcam_config.aec2); +} + +void CmndWebcamAGC(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.agc = XdrvMailbox.payload; + WcSetOptions(14, Settings->webcam_config.agc); + } + ResponseCmndStateText(Settings->webcam_config.agc); +} + +void CmndWebcamAGCGain(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 30)) { + Settings->webcam_config2.agc_gain = XdrvMailbox.payload; + WcSetOptions(15, Settings->webcam_config2.agc_gain); + } + ResponseCmndNumber(Settings->webcam_config2.agc_gain); +} + +void CmndWebcamGainCeiling(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) { + Settings->webcam_config2.gainceiling = XdrvMailbox.payload; + WcSetOptions(16, Settings->webcam_config2.gainceiling); + } + ResponseCmndNumber(Settings->webcam_config2.gainceiling); +} + +void CmndWebcamGammaCorrect(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.raw_gma = XdrvMailbox.payload; + WcSetOptions(17, Settings->webcam_config.raw_gma); + } + ResponseCmndStateText(Settings->webcam_config.raw_gma); +} + +void CmndWebcamLensCorrect(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.lenc = XdrvMailbox.payload; + WcSetOptions(18, Settings->webcam_config.lenc); + } + ResponseCmndStateText(Settings->webcam_config.lenc); +} + +void CmndWebcamWPC(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.wpc = XdrvMailbox.payload; + WcSetOptions(19, Settings->webcam_config.wpc); + } + ResponseCmndStateText(Settings->webcam_config.wpc); +} + +void CmndWebcamDCW(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.dcw = XdrvMailbox.payload; + WcSetOptions(20, Settings->webcam_config.dcw); + } + ResponseCmndStateText(Settings->webcam_config.dcw); +} + +void CmndWebcamBPC(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.bpc = XdrvMailbox.payload; + WcSetOptions(21, Settings->webcam_config.bpc); + } + ResponseCmndStateText(Settings->webcam_config.bpc); +} + +void CmndWebcamColorbar(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings->webcam_config.colorbar = XdrvMailbox.payload; + WcSetOptions(22, Settings->webcam_config.colorbar); + } + ResponseCmndStateText(Settings->webcam_config.colorbar); +} + +void CmndWebcamFeature(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { + Settings->webcam_config.feature = XdrvMailbox.payload; + WcSetOptions(23, Settings->webcam_config.feature); + } + ResponseCmndNumber(Settings->webcam_config.feature); +} + void CmndWebcamInit(void) { WcInterruptControl(); ResponseCmndDone(); } +void CmndWebcamSetDefaults(void) { + WcSetDefaults(0); + ResponseCmndDone(); +} + +#define D_WEBCAM_STATS_FPS "FPS" +#define D_WEBCAM_STATS_CAMFAIL "CamFail" +#define D_WEBCAM_STATS_JPEGFAIL "JpegFail" +#define D_WEBCAM_STATS_CLIENTFAIL "ClientFail" + +void CmndWebcamStats(void) { + Response_P(PSTR("{\"" D_PRFX_WEBCAM D_CMND_WC_STATS "\":{\"" D_WEBCAM_STATS_FPS "\":%d,\"" + D_WEBCAM_STATS_CAMFAIL "\":%d,\"" D_WEBCAM_STATS_JPEGFAIL "\":%d,\"" D_WEBCAM_STATS_CLIENTFAIL "\":%d" + "}}"), + WcStats.camfps, WcStats.camfail, WcStats.jpegfail, WcStats.clientfail + ); +} + #ifdef ENABLE_RTSPSERVER void CmndWebRtsp(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { @@ -1100,6 +1531,19 @@ void CmndWebRtsp(void) { } #endif // ENABLE_RTSPSERVER +void WcUpdateStats(void) { + WcStats.camfps = WcStats.camcnt; + WcStats.camcnt = 0; +} + +#define D_UNIT_FPS "FPS" +const char HTTP_WEBCAM_FPS[] PROGMEM = "{s}%s Frames per Second {m}%d " D_UNIT_FPS "{e}"; + +void WcStatsShow(void) { +#ifdef USE_WEBSERVER + WSContentSend_PD(HTTP_WEBCAM_FPS, WcStats.name, WcStats.camfps); +#endif // USE_WEBSERVER +} /*********************************************************************************************\ * Interface @@ -1118,6 +1562,11 @@ bool Xdrv81(uint8_t function) { case FUNC_WEB_ADD_MAIN_BUTTON: WcShowStream(); break; + case FUNC_EVERY_SECOND: + WcUpdateStats(); + case FUNC_WEB_SENSOR: + WcStatsShow(); + break; case FUNC_COMMAND: result = DecodeCommand(kWCCommands, WCCommand); break;