Skip to content

Commit 04601d8

Browse files
committed
config: gain control & gain ceiling
refs #16
1 parent f1c8c7f commit 04601d8

File tree

3 files changed

+62
-16
lines changed

3 files changed

+62
-16
lines changed

examples/AsyncCam/handlers.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ static const char FRONTPAGE[] = R"EOT(
1111
%brightness%
1212
%contrast%
1313
%saturation%
14+
<select name="gain" title="gain">%gain%</select>
1415
<select name="lightMode" title="light mode">%lightMode%</select>
1516
<select name="specialEffect" title="special effect">%specialEffect%</select>
1617
%hmirror%
@@ -78,11 +79,25 @@ rewriteFrontpage(const esp32cam::Settings& s, const String& var) {
7879
b.print(r);
7980
b.print("</option>");
8081
}
82+
} else if (var == "gain") {
83+
#define SHOW_GAIN(val, dsp) \
84+
b.printf("<option value=\"%d\"%s>%dx</option>", val, s.gain == val ? " selected" : "", dsp)
85+
b.printf("<optgroup label=\"AGC=off\">");
86+
for (int i = 1; i <= 31; ++i) {
87+
SHOW_GAIN(i, i);
88+
}
89+
b.printf("</optgroup>");
90+
b.printf("<optgroup label=\"AGC=on\">");
91+
for (int i = 2; i <= 128; i <<= 1) {
92+
SHOW_GAIN(-i, i);
93+
}
94+
b.printf("</optgroup>");
95+
#undef SHOW_GAIN
8196
} else if (var == "lightMode") {
82-
#define SHOW_LM(MODE, SYMBOL) \
97+
#define SHOW_LM(MODE, symbol) \
8398
b.printf("<option value=\"%d\" title=\"%s\"%s>%s</option>", \
8499
static_cast<int>(esp32cam::LightMode::MODE), #MODE, \
85-
s.lightMode == esp32cam::LightMode::MODE ? " selected" : "", SYMBOL)
100+
s.lightMode == esp32cam::LightMode::MODE ? " selected" : "", symbol)
86101
SHOW_LM(NONE, "&#x1F6AB;");
87102
SHOW_LM(AUTO, "&#x2B55;");
88103
SHOW_LM(SUNNY, "&#x2600;&#xFE0F;");
@@ -91,10 +106,10 @@ rewriteFrontpage(const esp32cam::Settings& s, const String& var) {
91106
SHOW_LM(HOME, "&#x1F3E0;");
92107
#undef SHOW_LM
93108
} else if (var == "specialEffect") {
94-
#define SHOW_SE(MODE, SYMBOL) \
109+
#define SHOW_SE(MODE, symbol) \
95110
b.printf("<option value=\"%d\" title=\"%s\"%s>%s</option>", \
96111
static_cast<int>(esp32cam::SpecialEffect::MODE), #MODE, \
97-
s.specialEffect == esp32cam::SpecialEffect::MODE ? " selected" : "", SYMBOL)
112+
s.specialEffect == esp32cam::SpecialEffect::MODE ? " selected" : "", symbol)
98113
SHOW_SE(NONE, "&#x1F6AB;");
99114
SHOW_SE(NEGATIVE, "&#x2B1C;");
100115
SHOW_SE(BLACKWHITE, "&#x2B1B;");
@@ -144,6 +159,7 @@ handleUpdate(AsyncWebServerRequest* req) {
144159
SAVE_INT(brightness);
145160
SAVE_INT(contrast);
146161
SAVE_INT(saturation);
162+
SAVE_INT(gain);
147163
SAVE_INT(lightMode);
148164
SAVE_INT(specialEffect);
149165
SAVE_BOOL(hmirror);

src/esp32cam/config.cpp

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ CameraClass::status() const {
107107
result.saturation = ss.saturation;
108108
result.lightMode = ss.awb_gain ? static_cast<LightMode>(ss.wb_mode) : LightMode::NONE;
109109
result.specialEffect = static_cast<SpecialEffect>(ss.special_effect);
110+
if (ss.agc) {
111+
result.gain = (-2) << ss.gainceiling;
112+
} else {
113+
result.gain = 1 + static_cast<int8_t>(ss.agc_gain);
114+
}
110115
result.hmirror = ss.hmirror != 0;
111116
result.vflip = ss.vflip != 0;
112117
return result;
@@ -128,44 +133,61 @@ CameraClass::update(const Settings& settings, int sleepFor) {
128133
} \
129134
} while (false)
130135

131-
#define UPDATE(STATUS_MEM, value, SETTER_TYP) \
136+
#define UPDATE4(STATUS_MEM, value, SETTER_MEM, SETTER_TYP) \
132137
do { \
133138
int prev = static_cast<int>(sensor->status.STATUS_MEM); \
134139
int desired = static_cast<int>(value); \
135140
if (prev != desired) { \
136-
int res = sensor->set_##STATUS_MEM(sensor, static_cast<SETTER_TYP>(desired)); \
141+
int res = sensor->SETTER_MEM(sensor, static_cast<SETTER_TYP>(desired)); \
137142
ESP32CAM_LOG("update " #STATUS_MEM " %d => %d %s", prev, desired, \
138143
res == 0 ? "success" : "failure"); \
139144
if (res != 0) { \
140145
return false; \
141146
} \
142147
} \
143148
} while (false)
144-
#define UPDATE1(MEM) UPDATE(MEM, settings.MEM, int)
149+
#define UPDATE3(STATUS_MEM, value, SETTER_TYP) \
150+
UPDATE4(STATUS_MEM, (value), set_##STATUS_MEM, SETTER_TYP)
151+
#define UPDATE2(STATUS_MEM, value) UPDATE3(STATUS_MEM, (value), int)
152+
#define UPDATE1(MEM) UPDATE2(MEM, settings.MEM)
145153

146154
CHECK_RANGE(brightness, -2, 2);
147155
CHECK_RANGE(contrast, -2, 2);
148156
CHECK_RANGE(saturation, -2, 2);
149157
CHECK_RANGE(lightMode, -1, 4);
150158
CHECK_RANGE(specialEffect, 0, 6);
159+
CHECK_RANGE(gain, -128, 31);
151160

152-
UPDATE(framesize, settings.resolution.as<framesize_t>(), framesize_t);
161+
UPDATE3(framesize, settings.resolution.as<framesize_t>(), framesize_t);
153162
UPDATE1(brightness);
154163
UPDATE1(contrast);
155164
UPDATE1(saturation);
165+
UPDATE2(special_effect, settings.specialEffect);
166+
UPDATE1(hmirror);
167+
UPDATE1(vflip);
168+
169+
if (settings.gain > 0) {
170+
UPDATE4(agc, 0, set_gain_ctrl, int);
171+
UPDATE2(agc_gain, settings.gain - 1);
172+
UPDATE3(gainceiling, 0, gainceiling_t);
173+
} else {
174+
UPDATE4(agc, 1, set_gain_ctrl, int);
175+
UPDATE2(agc_gain, 0);
176+
UPDATE3(gainceiling, __builtin_ctz(static_cast<uint32_t>(-settings.gain)) - 1, gainceiling_t);
177+
}
178+
156179
if (settings.lightMode == LightMode::NONE) {
157-
UPDATE(awb_gain, 0, int);
158-
UPDATE(wb_mode, 0, int);
180+
UPDATE2(awb_gain, 0);
181+
UPDATE2(wb_mode, 0);
159182
} else {
160-
UPDATE(awb_gain, 1, int);
161-
UPDATE(wb_mode, settings.lightMode, int);
183+
UPDATE2(awb_gain, 1);
184+
UPDATE2(wb_mode, settings.lightMode);
162185
}
163-
UPDATE(special_effect, settings.specialEffect, int);
164-
UPDATE1(hmirror);
165-
UPDATE1(vflip);
166186

167187
#undef CHECK_RANGE
168-
#undef UPDATE
188+
#undef UPDATE4
189+
#undef UPDATE3
190+
#undef UPDATE2
169191
#undef UPDATE1
170192

171193
if (sleepFor > 0) {

src/esp32cam/config.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ struct Settings {
8787
/** @brief Image saturation, between -2 and +2. */
8888
int8_t saturation;
8989

90+
/**
91+
* @brief Gain control, with or without Automatic Gain Control (AGC).
92+
*
93+
* - AGC disabled: a positive number between 1 and 31, which corresponds to 1x ~ 31x gain.
94+
* - AGC enabled: -2,-4,-8,-16,-32,-64,-128, which corresponds to 2x ~ 128x gain.
95+
*/
96+
int8_t gain;
97+
9098
/** @brief Image light mode. */
9199
LightMode lightMode;
92100

0 commit comments

Comments
 (0)