Skip to content

Commit

Permalink
config: gain control & gain ceiling
Browse files Browse the repository at this point in the history
refs #16
  • Loading branch information
yoursunny committed Jan 12, 2025
1 parent f1c8c7f commit 04601d8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 16 deletions.
24 changes: 20 additions & 4 deletions examples/AsyncCam/handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ static const char FRONTPAGE[] = R"EOT(
%brightness%
%contrast%
%saturation%
<select name="gain" title="gain">%gain%</select>
<select name="lightMode" title="light mode">%lightMode%</select>
<select name="specialEffect" title="special effect">%specialEffect%</select>
%hmirror%
Expand Down Expand Up @@ -78,11 +79,25 @@ rewriteFrontpage(const esp32cam::Settings& s, const String& var) {
b.print(r);
b.print("</option>");
}
} else if (var == "gain") {
#define SHOW_GAIN(val, dsp) \
b.printf("<option value=\"%d\"%s>%dx</option>", val, s.gain == val ? " selected" : "", dsp)
b.printf("<optgroup label=\"AGC=off\">");
for (int i = 1; i <= 31; ++i) {
SHOW_GAIN(i, i);
}
b.printf("</optgroup>");
b.printf("<optgroup label=\"AGC=on\">");
for (int i = 2; i <= 128; i <<= 1) {
SHOW_GAIN(-i, i);
}
b.printf("</optgroup>");
#undef SHOW_GAIN
} else if (var == "lightMode") {
#define SHOW_LM(MODE, SYMBOL) \
#define SHOW_LM(MODE, symbol) \
b.printf("<option value=\"%d\" title=\"%s\"%s>%s</option>", \
static_cast<int>(esp32cam::LightMode::MODE), #MODE, \
s.lightMode == esp32cam::LightMode::MODE ? " selected" : "", SYMBOL)
s.lightMode == esp32cam::LightMode::MODE ? " selected" : "", symbol)
SHOW_LM(NONE, "&#x1F6AB;");
SHOW_LM(AUTO, "&#x2B55;");
SHOW_LM(SUNNY, "&#x2600;&#xFE0F;");
Expand All @@ -91,10 +106,10 @@ rewriteFrontpage(const esp32cam::Settings& s, const String& var) {
SHOW_LM(HOME, "&#x1F3E0;");
#undef SHOW_LM
} else if (var == "specialEffect") {
#define SHOW_SE(MODE, SYMBOL) \
#define SHOW_SE(MODE, symbol) \
b.printf("<option value=\"%d\" title=\"%s\"%s>%s</option>", \
static_cast<int>(esp32cam::SpecialEffect::MODE), #MODE, \
s.specialEffect == esp32cam::SpecialEffect::MODE ? " selected" : "", SYMBOL)
s.specialEffect == esp32cam::SpecialEffect::MODE ? " selected" : "", symbol)
SHOW_SE(NONE, "&#x1F6AB;");
SHOW_SE(NEGATIVE, "&#x2B1C;");
SHOW_SE(BLACKWHITE, "&#x2B1B;");
Expand Down Expand Up @@ -144,6 +159,7 @@ handleUpdate(AsyncWebServerRequest* req) {
SAVE_INT(brightness);
SAVE_INT(contrast);
SAVE_INT(saturation);
SAVE_INT(gain);
SAVE_INT(lightMode);
SAVE_INT(specialEffect);
SAVE_BOOL(hmirror);
Expand Down
46 changes: 34 additions & 12 deletions src/esp32cam/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ CameraClass::status() const {
result.saturation = ss.saturation;
result.lightMode = ss.awb_gain ? static_cast<LightMode>(ss.wb_mode) : LightMode::NONE;
result.specialEffect = static_cast<SpecialEffect>(ss.special_effect);
if (ss.agc) {
result.gain = (-2) << ss.gainceiling;
} else {
result.gain = 1 + static_cast<int8_t>(ss.agc_gain);
}
result.hmirror = ss.hmirror != 0;
result.vflip = ss.vflip != 0;
return result;
Expand All @@ -128,44 +133,61 @@ CameraClass::update(const Settings& settings, int sleepFor) {
} \
} while (false)

#define UPDATE(STATUS_MEM, value, SETTER_TYP) \
#define UPDATE4(STATUS_MEM, value, SETTER_MEM, SETTER_TYP) \
do { \
int prev = static_cast<int>(sensor->status.STATUS_MEM); \
int desired = static_cast<int>(value); \
if (prev != desired) { \
int res = sensor->set_##STATUS_MEM(sensor, static_cast<SETTER_TYP>(desired)); \
int res = sensor->SETTER_MEM(sensor, static_cast<SETTER_TYP>(desired)); \
ESP32CAM_LOG("update " #STATUS_MEM " %d => %d %s", prev, desired, \
res == 0 ? "success" : "failure"); \
if (res != 0) { \
return false; \
} \
} \
} while (false)
#define UPDATE1(MEM) UPDATE(MEM, settings.MEM, int)
#define UPDATE3(STATUS_MEM, value, SETTER_TYP) \
UPDATE4(STATUS_MEM, (value), set_##STATUS_MEM, SETTER_TYP)
#define UPDATE2(STATUS_MEM, value) UPDATE3(STATUS_MEM, (value), int)
#define UPDATE1(MEM) UPDATE2(MEM, settings.MEM)

CHECK_RANGE(brightness, -2, 2);
CHECK_RANGE(contrast, -2, 2);
CHECK_RANGE(saturation, -2, 2);
CHECK_RANGE(lightMode, -1, 4);
CHECK_RANGE(specialEffect, 0, 6);
CHECK_RANGE(gain, -128, 31);

UPDATE(framesize, settings.resolution.as<framesize_t>(), framesize_t);
UPDATE3(framesize, settings.resolution.as<framesize_t>(), framesize_t);
UPDATE1(brightness);
UPDATE1(contrast);
UPDATE1(saturation);
UPDATE2(special_effect, settings.specialEffect);
UPDATE1(hmirror);
UPDATE1(vflip);

if (settings.gain > 0) {
UPDATE4(agc, 0, set_gain_ctrl, int);
UPDATE2(agc_gain, settings.gain - 1);
UPDATE3(gainceiling, 0, gainceiling_t);
} else {
UPDATE4(agc, 1, set_gain_ctrl, int);
UPDATE2(agc_gain, 0);
UPDATE3(gainceiling, __builtin_ctz(static_cast<uint32_t>(-settings.gain)) - 1, gainceiling_t);
}

if (settings.lightMode == LightMode::NONE) {
UPDATE(awb_gain, 0, int);
UPDATE(wb_mode, 0, int);
UPDATE2(awb_gain, 0);
UPDATE2(wb_mode, 0);
} else {
UPDATE(awb_gain, 1, int);
UPDATE(wb_mode, settings.lightMode, int);
UPDATE2(awb_gain, 1);
UPDATE2(wb_mode, settings.lightMode);
}
UPDATE(special_effect, settings.specialEffect, int);
UPDATE1(hmirror);
UPDATE1(vflip);

#undef CHECK_RANGE
#undef UPDATE
#undef UPDATE4
#undef UPDATE3
#undef UPDATE2
#undef UPDATE1

if (sleepFor > 0) {
Expand Down
8 changes: 8 additions & 0 deletions src/esp32cam/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ struct Settings {
/** @brief Image saturation, between -2 and +2. */
int8_t saturation;

/**
* @brief Gain control, with or without Automatic Gain Control (AGC).
*
* - AGC disabled: a positive number between 1 and 31, which corresponds to 1x ~ 31x gain.
* - AGC enabled: -2,-4,-8,-16,-32,-64,-128, which corresponds to 2x ~ 128x gain.
*/
int8_t gain;

/** @brief Image light mode. */
LightMode lightMode;

Expand Down

0 comments on commit 04601d8

Please sign in to comment.