@@ -277,32 +277,131 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
277277 return 0 ;
278278}
279279
280- static int set_contrast (sensor_t * sensor , int contrast )
280+ static int set_contrast (sensor_t * sensor , int level )
281281{
282- if ( contrast > 0 ) {
283- sensor -> status . contrast = contrast ;
284- write_reg ( sensor -> slv_addr , 0xfe , 0x00 );
285- write_reg ( sensor -> slv_addr , 0xb3 , contrast ) ;
282+ int ret = 0 ;
283+ // GC0308 contrast range: -2 to +2 (mapped to register values)
284+ if ( level < -2 || level > 2 ) {
285+ return -1 ;
286286 }
287- return 0 ;
287+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
288+ // Adjust contrast (CONTRAST register)
289+ // Default value is 0x40, adjust based on level
290+ uint8_t contrast_val = 0x40 + (level * 0x10 );
291+ ret |= write_reg (sensor -> slv_addr , CONTRAST , contrast_val );
292+ if (ret == 0 ) {
293+ sensor -> status .contrast = level ;
294+ ESP_LOGD (TAG , "Set contrast to: %d" , level );
295+ }
296+ return ret ;
288297}
289298
290- static int set_global_gain (sensor_t * sensor , int gain_level )
299+ static int set_brightness (sensor_t * sensor , int level )
291300{
292- if (gain_level != 0 ) {
293- write_reg (sensor -> slv_addr , 0xfe , 0x00 );
294- write_reg (sensor -> slv_addr , 0x50 , gain_level );
301+ int ret = 0 ;
302+ // GC0308 brightness range: -2 to +2 (mapped to register values)
303+ if (level < -2 || level > 2 ) {
304+ return -1 ;
295305 }
296- return 0 ;
306+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
307+ // Adjust brightness via LSC target Y base (LSC_RED_B2)
308+ // Default value is 0x48, adjust based on level
309+ uint8_t brightness_val = 0x48 + (level * 0x10 );
310+ ret |= write_reg (sensor -> slv_addr , LSC_RED_B2 , brightness_val );
311+ if (ret == 0 ) {
312+ sensor -> status .brightness = level ;
313+ ESP_LOGD (TAG , "Set brightness to: %d" , level );
314+ }
315+ return ret ;
316+ }
317+
318+ static int set_saturation (sensor_t * sensor , int level )
319+ {
320+ int ret = 0 ;
321+ // GC0308 saturation range: -2 to +2
322+ if (level < -2 || level > 2 ) {
323+ return -1 ;
324+ }
325+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
326+ // Adjust saturation via Cb and Cr gain (SATURATION_CB1, SATURATION_CR1)
327+ // Default values: SATURATION_CB=0xcb, SATURATION_CB1=0x10, SATURATION_CR1=0x90
328+ uint8_t sat_base = 0x40 + (level * 0x10 );
329+ ret |= write_reg (sensor -> slv_addr , SATURATION_CB1 , sat_base );
330+ ret |= write_reg (sensor -> slv_addr , SATURATION_CR1 , sat_base + 0x50 );
331+ if (ret == 0 ) {
332+ sensor -> status .saturation = level ;
333+ ESP_LOGD (TAG , "Set saturation to: %d" , level );
334+ }
335+ return ret ;
336+ }
337+
338+ static int set_sharpness (sensor_t * sensor , int level )
339+ {
340+ int ret = 0 ;
341+ // GC0308 sharpness range: -2 to +2
342+ if (level < -2 || level > 2 ) {
343+ return -1 ;
344+ }
345+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
346+ // Adjust sharpness via edge enhancement (EDGE_DEC_SA1-SA3)
347+ // Lower values = less sharp, higher values = more sharp
348+ uint8_t sharp_val = 0x20 + (level * 0x08 );
349+ ret |= write_reg (sensor -> slv_addr , EDGE_DEC_SA1 , sharp_val );
350+ ret |= write_reg (sensor -> slv_addr , EDGE_DEC_SA2 , sharp_val );
351+ ret |= write_reg (sensor -> slv_addr , EDGE_DEC_SA3 , sharp_val );
352+ if (ret == 0 ) {
353+ sensor -> status .sharpness = level ;
354+ ESP_LOGD (TAG , "Set sharpness to: %d" , level );
355+ }
356+ return ret ;
357+ }
358+
359+ static int set_whitebal (sensor_t * sensor , int enable )
360+ {
361+ int ret = 0 ;
362+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
363+ // AWB enable/disable via AEC_MODE1 register, AWB_ENABLE bit
364+ ret |= set_reg_bits (sensor -> slv_addr , AEC_MODE1 , 1 , 0x01 , enable != 0 );
365+ if (ret == 0 ) {
366+ sensor -> status .awb = enable ;
367+ ESP_LOGD (TAG , "Set AWB to: %d" , enable );
368+ }
369+ return ret ;
370+ }
371+
372+ static int set_gain_ctrl (sensor_t * sensor , int enable )
373+ {
374+ int ret = 0 ;
375+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
376+ // AGC enable/disable via AEC_MODE1 register, AGC_ENABLE bit
377+ ret |= set_reg_bits (sensor -> slv_addr , AEC_MODE1 , 2 , 0x01 , enable != 0 );
378+ if (ret == 0 ) {
379+ sensor -> status .agc = enable ;
380+ ESP_LOGD (TAG , "Set AGC to: %d" , enable );
381+ }
382+ return ret ;
383+ }
384+
385+ static int set_exposure_ctrl (sensor_t * sensor , int enable )
386+ {
387+ int ret = 0 ;
388+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
389+ // AEC enable/disable via AEC_MODE1 register, AEC_ENABLE bit
390+ ret |= set_reg_bits (sensor -> slv_addr , AEC_MODE1 , 0 , 0x01 , enable != 0 );
391+ if (ret == 0 ) {
392+ sensor -> status .aec = enable ;
393+ ESP_LOGD (TAG , "Set AEC to: %d" , enable );
394+ }
395+ return ret ;
297396}
298397
299398static int set_hmirror (sensor_t * sensor , int enable )
300399{
301400 int ret = 0 ;
302- sensor -> status .hmirror = enable ;
303401 ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
304- ret |= set_reg_bits (sensor -> slv_addr , 0x14 , 0 , 0x01 , enable != 0 );
402+ ret |= set_reg_bits (sensor -> slv_addr , CISCTL_MODE1 , 0 , 0x01 , enable != 0 );
305403 if (ret == 0 ) {
404+ sensor -> status .hmirror = enable ;
306405 ESP_LOGD (TAG , "Set h-mirror to: %d" , enable );
307406 }
308407 return ret ;
@@ -311,27 +410,176 @@ static int set_hmirror(sensor_t *sensor, int enable)
311410static int set_vflip (sensor_t * sensor , int enable )
312411{
313412 int ret = 0 ;
314- sensor -> status .vflip = enable ;
315413 ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
316- ret |= set_reg_bits (sensor -> slv_addr , 0x14 , 1 , 0x01 , enable != 0 );
414+ ret |= set_reg_bits (sensor -> slv_addr , CISCTL_MODE1 , 1 , 0x01 , enable != 0 );
317415 if (ret == 0 ) {
416+ sensor -> status .vflip = enable ;
318417 ESP_LOGD (TAG , "Set v-flip to: %d" , enable );
319418 }
320419 return ret ;
321420}
322421
422+
423+ static int set_agc_gain (sensor_t * sensor , int gain )
424+ {
425+ int ret = 0 ;
426+ // GC0308 AGC gain range: 0-30 (standard sensor API range)
427+ // Maps to hardware register values 0x00-0x3F (6-bit effective range)
428+ // Hardware default is 0x14 (20)
429+ if (gain < 0 ) {
430+ gain = 0 ;
431+ } else if (gain > 30 ) {
432+ gain = 30 ;
433+ }
434+ // Map API range 0-30 to hardware range 0-63 (approximately 2x multiplier)
435+ uint8_t gain_value = (gain * 63 ) / 30 ;
436+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
437+ ret |= write_reg (sensor -> slv_addr , GLOBAL_GAIN , gain_value );
438+ if (ret == 0 ) {
439+ sensor -> status .agc_gain = gain ;
440+ ESP_LOGD (TAG , "Set AGC gain to: %d (hw: 0x%02x)" , gain , gain_value );
441+ }
442+ return ret ;
443+ }
444+
323445static int set_colorbar (sensor_t * sensor , int enable )
324446{
325447 int ret = 0 ;
326448 ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
327- ret |= set_reg_bits (sensor -> slv_addr , 0x2e , 0 , 0x01 , enable );
449+ ret |= set_reg_bits (sensor -> slv_addr , OUT_CTRL , 0 , 0x01 , enable );
328450 if (ret == 0 ) {
329451 sensor -> status .colorbar = enable ;
330452 ESP_LOGD (TAG , "Set colorbar to: %d" , enable );
331453 }
332454 return ret ;
333455}
334456
457+ static int set_special_effect (sensor_t * sensor , int effect )
458+ {
459+ int ret = 0 ;
460+ // Effect values: 0=Normal, 1=Negative, 2=Grayscale, 3=Red Tint, 4=Green Tint, 5=Blue Tint, 6=Sepia
461+ if (effect < 0 || effect > 6 ) {
462+ return -1 ;
463+ }
464+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
465+ switch (effect ) {
466+ case 0 : // Normal
467+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_NORMAL );
468+ ret |= write_reg (sensor -> slv_addr , EFFECT_MODE , 0x0a );
469+ ret |= write_reg (sensor -> slv_addr , FIXED_CB , 0x7f );
470+ ret |= write_reg (sensor -> slv_addr , FIXED_CR , 0xfa );
471+ break ;
472+ case 1 : // Negative
473+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_NEGATIVE );
474+ break ;
475+ case 2 : // Grayscale (B&W)
476+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_GRAYSCALE );
477+ ret |= write_reg (sensor -> slv_addr , EFFECT_MODE , 0x0a );
478+ ret |= write_reg (sensor -> slv_addr , FIXED_CB , 0x7f );
479+ ret |= write_reg (sensor -> slv_addr , FIXED_CR , 0xfa );
480+ break ;
481+ case 3 : // Red Tint
482+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_GRAYSCALE );
483+ ret |= write_reg (sensor -> slv_addr , EFFECT_MODE , 0x0a );
484+ ret |= write_reg (sensor -> slv_addr , FIXED_CB , 0x80 );
485+ ret |= write_reg (sensor -> slv_addr , FIXED_CR , 0xc0 );
486+ break ;
487+ case 4 : // Green Tint
488+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_GRAYSCALE );
489+ ret |= write_reg (sensor -> slv_addr , EFFECT_MODE , 0x0a );
490+ ret |= write_reg (sensor -> slv_addr , FIXED_CB , 0x50 );
491+ ret |= write_reg (sensor -> slv_addr , FIXED_CR , 0x50 );
492+ break ;
493+ case 5 : // Blue Tint
494+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_GRAYSCALE );
495+ ret |= write_reg (sensor -> slv_addr , EFFECT_MODE , 0x0a );
496+ ret |= write_reg (sensor -> slv_addr , FIXED_CB , 0xa0 );
497+ ret |= write_reg (sensor -> slv_addr , FIXED_CR , 0x80 );
498+ break ;
499+ case 6 : // Sepia
500+ ret |= set_reg_bits (sensor -> slv_addr , SPECIAL_EFFECT , 0 , 0x03 , EFFECT_GRAYSCALE );
501+ ret |= write_reg (sensor -> slv_addr , EFFECT_MODE , 0x0a );
502+ ret |= write_reg (sensor -> slv_addr , FIXED_CB , 0xd0 );
503+ ret |= write_reg (sensor -> slv_addr , FIXED_CR , 0x28 );
504+ break ;
505+ default :
506+ ret = -1 ;
507+ break ;
508+ }
509+ if (ret == 0 ) {
510+ sensor -> status .special_effect = effect ;
511+ ESP_LOGD (TAG , "Set special effect to: %d" , effect );
512+ }
513+ return ret ;
514+ }
515+
516+ static int set_wb_mode (sensor_t * sensor , int mode )
517+ {
518+ int ret = 0 ;
519+ // WB modes: 0=Auto, 1=Sunny, 2=Cloudy, 3=Office, 4=Home
520+ if (mode < 0 || mode > 4 ) {
521+ return -1 ;
522+ }
523+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x00 );
524+ if (mode == 0 ) {
525+ // Auto WB - enable AWB via AEC_MODE1
526+ ret |= set_reg_bits (sensor -> slv_addr , AEC_MODE1 , 1 , 0x01 , 1 );
527+ } else {
528+ // Manual WB - disable AWB and set specific gains
529+ ret |= set_reg_bits (sensor -> slv_addr , AEC_MODE1 , 1 , 0x01 , 0 );
530+ switch (mode ) {
531+ case 1 : // Sunny
532+ ret |= write_reg (sensor -> slv_addr , AWB_R_GAIN , 0x74 );
533+ ret |= write_reg (sensor -> slv_addr , AWB_G_GAIN , 0x52 );
534+ ret |= write_reg (sensor -> slv_addr , AWB_B_GAIN , 0x40 );
535+ break ;
536+ case 2 : // Cloudy
537+ ret |= write_reg (sensor -> slv_addr , AWB_R_GAIN , 0x8c );
538+ ret |= write_reg (sensor -> slv_addr , AWB_G_GAIN , 0x50 );
539+ ret |= write_reg (sensor -> slv_addr , AWB_B_GAIN , 0x40 );
540+ break ;
541+ case 3 : // Office
542+ ret |= write_reg (sensor -> slv_addr , AWB_R_GAIN , 0x48 );
543+ ret |= write_reg (sensor -> slv_addr , AWB_G_GAIN , 0x40 );
544+ ret |= write_reg (sensor -> slv_addr , AWB_B_GAIN , 0x5c );
545+ break ;
546+ case 4 : // Home
547+ ret |= write_reg (sensor -> slv_addr , AWB_R_GAIN , 0x40 );
548+ ret |= write_reg (sensor -> slv_addr , AWB_G_GAIN , 0x54 );
549+ ret |= write_reg (sensor -> slv_addr , AWB_B_GAIN , 0x70 );
550+ break ;
551+ default :
552+ ret = -1 ;
553+ break ;
554+ }
555+ }
556+ if (ret == 0 ) {
557+ sensor -> status .wb_mode = mode ;
558+ ESP_LOGD (TAG , "Set WB mode to: %d" , mode );
559+ }
560+ return ret ;
561+ }
562+
563+ static int set_ae_level (sensor_t * sensor , int level )
564+ {
565+ int ret = 0 ;
566+ // AE level range: -2 to +2
567+ if (level < -2 || level > 2 ) {
568+ return -1 ;
569+ }
570+ ret = write_reg (sensor -> slv_addr , 0xfe , 0x01 );
571+ // Adjust AE target via AEC_TARGET_Y register (Page 1)
572+ // Default is around 0x19, adjust based on level
573+ uint8_t ae_target = 0x19 + (level * 0x08 );
574+ ret |= write_reg (sensor -> slv_addr , AEC_TARGET_Y , ae_target );
575+ ret |= write_reg (sensor -> slv_addr , 0xfe , 0x00 );
576+ if (ret == 0 ) {
577+ sensor -> status .ae_level = level ;
578+ ESP_LOGD (TAG , "Set AE level to: %d" , level );
579+ }
580+ return ret ;
581+ }
582+
335583static int get_reg (sensor_t * sensor , int reg , int mask )
336584{
337585 int ret = 0 ;
@@ -433,27 +681,27 @@ int gc0308_init(sensor_t *sensor)
433681 sensor -> set_pixformat = set_pixformat ;
434682 sensor -> set_framesize = set_framesize ;
435683 sensor -> set_contrast = set_contrast ;
436- sensor -> set_brightness = set_dummy ;
437- sensor -> set_saturation = set_dummy ;
438- sensor -> set_sharpness = set_dummy ;
684+ sensor -> set_brightness = set_brightness ;
685+ sensor -> set_saturation = set_saturation ;
686+ sensor -> set_sharpness = set_sharpness ;
439687 sensor -> set_denoise = set_dummy ;
440688 sensor -> set_gainceiling = set_gainceiling_dummy ;
441689 sensor -> set_quality = set_dummy ;
442690 sensor -> set_colorbar = set_colorbar ;
443- sensor -> set_whitebal = set_dummy ;
444- sensor -> set_gain_ctrl = set_global_gain ;
445- sensor -> set_exposure_ctrl = set_dummy ;
691+ sensor -> set_whitebal = set_whitebal ;
692+ sensor -> set_gain_ctrl = set_gain_ctrl ;
693+ sensor -> set_exposure_ctrl = set_exposure_ctrl ;
446694 sensor -> set_hmirror = set_hmirror ;
447695 sensor -> set_vflip = set_vflip ;
448696
449697 sensor -> set_aec2 = set_dummy ;
450698 sensor -> set_awb_gain = set_dummy ;
451- sensor -> set_agc_gain = set_dummy ;
699+ sensor -> set_agc_gain = set_agc_gain ;
452700 sensor -> set_aec_value = set_dummy ;
453701
454- sensor -> set_special_effect = set_dummy ;
455- sensor -> set_wb_mode = set_dummy ;
456- sensor -> set_ae_level = set_dummy ;
702+ sensor -> set_special_effect = set_special_effect ;
703+ sensor -> set_wb_mode = set_wb_mode ;
704+ sensor -> set_ae_level = set_ae_level ;
457705
458706 sensor -> set_dcw = set_dummy ;
459707 sensor -> set_bpc = set_dummy ;
0 commit comments