1 /*
2 * Copyright (c) 2019 Rockchip Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 #include "sample_comm.h"
19
20 #ifdef SAMPLE_SMART_IR
21
22 #include <fcntl.h>
23 #include <linux/v4l2-subdev.h>
24 #include <linux/videodev2.h>
25 #include <sys/ioctl.h>
26 #include <unistd.h>
27
28 #include "rk_smart_ir_api.h"
29 #include "uAPI2/rk_aiq_user_api2_ae.h"
30 #include "uAPI2/rk_aiq_user_api2_awb.h"
31 #include "uAPI2/rk_aiq_user_api2_sysctl.h"
32
33 #define RK_SMART_IR_AUTO_IRLED true
34
sample_smartIr_usage()35 static void sample_smartIr_usage()
36 {
37 printf("Usage : \n");
38 printf(" SmartIr API: \n");
39 printf("\t s) SmartIr: Start SmartIr test.\n");
40 printf("\t e) SmartIr: Exit SmartIr test.\n");
41 printf("\t c) SmartIr: Ir wb calibration.\n");
42 printf("\n");
43 printf("\t h) SmartIr: help.\n");
44 printf("\t q) SmartIr: return to main sample screen.\n");
45
46 printf("\n");
47 printf("\t please press the key: ");
48
49 return;
50 }
51
sample_print_smartIr_info(const void * arg)52 void sample_print_smartIr_info(const void* arg)
53 {
54 printf("enter SmartIr modult test!\n");
55 }
56
57 typedef struct sample_smartIr_s {
58 pthread_t tid;
59 bool tquit;
60 const rk_aiq_sys_ctx_t* aiq_ctx;
61 bool started;
62 const char* ir_cut_v4ldev;
63 const char* ir_v4ldev;
64 rk_smart_ir_ctx_t* ir_ctx;
65 rk_smart_ir_params_t ir_configs;
66 } sample_smartIr_t;
67
68 static sample_smartIr_t g_sample_smartIr_ctx;
69
enableIrCutter(bool on)70 static void enableIrCutter(bool on)
71 {
72 sample_smartIr_t* smartIr_ctx = &g_sample_smartIr_ctx;
73
74 struct v4l2_control control;
75
76 control.id = V4L2_CID_BAND_STOP_FILTER;
77 if (on)
78 control.value = 3; // filter ir
79 else
80 control.value = 0; // ir in
81
82 int _fd = open(smartIr_ctx->ir_cut_v4ldev, O_RDWR | O_CLOEXEC);
83 if (_fd != -1) {
84 if (ioctl(_fd, VIDIOC_S_CTRL, &control) < 0) {
85 printf("failed to set ircut value %d to device!\n", control.value);
86 }
87 close(_fd);
88 }
89 }
90
switch_to_day()91 static void switch_to_day()
92 {
93 // ir-cutter on
94 enableIrCutter(true);
95 // ir off
96 // switch to isp day params
97 }
98
switch_to_night()99 static void switch_to_night()
100 {
101 // switch to isp night params
102 // ir-cutter off
103 enableIrCutter(false);
104 // ir on
105 }
106
load_ir_configs()107 static void load_ir_configs()
108 {
109 sample_smartIr_t* smartIr_ctx = &g_sample_smartIr_ctx;
110 rk_smart_ir_result_t ir_init_res;
111
112 smartIr_ctx->ir_cut_v4ldev = NULL;
113 smartIr_ctx->ir_v4ldev = NULL;
114
115 smartIr_ctx->ir_cut_v4ldev = "/dev/v4l-subdev3";
116 smartIr_ctx->ir_configs.d2n_envL_th = 0.04f;
117 smartIr_ctx->ir_configs.n2d_envL_th = 0.20f;
118 smartIr_ctx->ir_configs.rggain_base = 1.0f;
119 smartIr_ctx->ir_configs.bggain_base = 1.0f;
120 smartIr_ctx->ir_configs.awbgain_rad = 0.10f;
121 smartIr_ctx->ir_configs.awbgain_dis = 0.22f;
122 smartIr_ctx->ir_configs.switch_cnts_th = 100;
123 rk_smart_ir_config(smartIr_ctx->ir_ctx, &smartIr_ctx->ir_configs);
124 // set initial status to day
125 ir_init_res.status = RK_SMART_IR_STATUS_DAY;
126 rk_smart_ir_set_status(smartIr_ctx->ir_ctx, ir_init_res);
127 switch_to_day();
128 }
129
switch_ir_thread(void * args)130 static void* switch_ir_thread(void* args)
131 {
132 sample_smartIr_t* smartIr_ctx = &g_sample_smartIr_ctx;
133 rk_smart_ir_result_t ir_res;
134 rk_aiq_isp_stats_t *stats_ref = NULL;
135 XCamReturn ret = XCAM_RETURN_NO_ERROR;
136
137 rk_smart_ir_autoled_t auto_irled = { 0 };
138 int irled_cur_value = 100;
139 if (RK_SMART_IR_AUTO_IRLED) {
140 // TODO: set init irled pwm duty
141 auto_irled.is_smooth_convert = false;
142 auto_irled.auto_irled_val = irled_cur_value;
143 auto_irled.auto_irled_min = 10;
144 auto_irled.auto_irled_max = 100;
145 }
146
147 while (!smartIr_ctx->tquit) {
148 ret = rk_aiq_uapi2_sysctl_get3AStatsBlk(smartIr_ctx->aiq_ctx, &stats_ref, -1);
149 if (ret == XCAM_RETURN_NO_ERROR && stats_ref != NULL) {
150 rk_smart_ir_runOnce(smartIr_ctx->ir_ctx, stats_ref, &ir_res);
151
152 rk_aiq_uapi2_sysctl_release3AStatsRef(smartIr_ctx->aiq_ctx, stats_ref);
153
154 if (RK_SMART_IR_AUTO_IRLED) {
155 rk_smart_ir_auto_irled(smartIr_ctx->ir_ctx, &auto_irled);
156 if (irled_cur_value != auto_irled.auto_irled_val) {
157 irled_cur_value = auto_irled.auto_irled_val;
158 // TODO: update irled pwm duty
159 }
160 }
161
162 if (ir_res.status == RK_SMART_IR_STATUS_DAY) {
163 switch_to_day();
164 } else if (ir_res.status == RK_SMART_IR_STATUS_NIGHT) {
165 switch_to_night();
166 } else {
167 }
168 printf("SAMPLE_SMART_IR: switch to %s\n", ir_res.status == RK_SMART_IR_STATUS_DAY ? "DAY" : "Night");
169 } else {
170 if (ret == XCAM_RETURN_NO_ERROR) {
171 printf("aiq has stopped !\n");
172 } else if (ret == XCAM_RETURN_ERROR_TIMEOUT) {
173 printf("aiq timeout!\n");
174 } else if (ret == XCAM_RETURN_ERROR_FAILED) {
175 printf("aiq failed!\n");
176 }
177 }
178 }
179
180 return NULL;
181 }
182
sample_smartIr_start(const void * arg)183 static void sample_smartIr_start(const void* arg)
184 {
185 const rk_aiq_sys_ctx_t* ctx = (rk_aiq_sys_ctx_t*)(arg);
186 sample_smartIr_t* smartIr_ctx = &g_sample_smartIr_ctx;
187
188 smartIr_ctx->ir_ctx = rk_smart_ir_init((rk_aiq_sys_ctx_t*)arg);
189 load_ir_configs();
190
191 smartIr_ctx->tquit = false;
192 pthread_create(&smartIr_ctx->tid, NULL, switch_ir_thread, NULL);
193 smartIr_ctx->started = true;
194 }
195
sample_smartIr_stop(const void * arg)196 static void sample_smartIr_stop(const void* arg)
197 {
198 const rk_aiq_sys_ctx_t* ctx = (rk_aiq_sys_ctx_t*)(arg);
199 sample_smartIr_t* smartIr_ctx = &g_sample_smartIr_ctx;
200
201 if (smartIr_ctx->started) {
202 smartIr_ctx->tquit = true;
203 pthread_join(smartIr_ctx->tid, NULL);
204 }
205 smartIr_ctx->started = false;
206
207 if (smartIr_ctx->ir_ctx) {
208 rk_smart_ir_deInit(smartIr_ctx->ir_ctx);
209 smartIr_ctx->ir_ctx = NULL;
210 }
211 }
212
sample_smartIr_calib(const void * arg)213 static void sample_smartIr_calib(const void* arg)
214 {
215 const rk_aiq_sys_ctx_t* ctx = (rk_aiq_sys_ctx_t*)(arg);
216
217 // 1. make sure no visible light
218 // 2. ircutter off, ir on
219 switch_to_night();
220 // 3. query wb info
221 rk_aiq_wb_querry_info_t wb_info;
222 float RGgain = 0.0f, BGgain = 0.0f;
223 int counts = 0;
224 rk_aiq_isp_stats_t *stats_ref = NULL;
225 printf("SmartIr Calib start ...... \n");
226 XCamReturn ret = XCAM_RETURN_NO_ERROR;
227 while (counts++ < 100) {
228 ret = rk_aiq_uapi2_sysctl_get3AStatsBlk(ctx, &stats_ref, -1);
229 if (ret == XCAM_RETURN_NO_ERROR && stats_ref != NULL) {
230 printf("stats frame id %d \n", stats_ref->frame_id);
231 if (stats_ref->awb_hw_ver == 4) { // isp32
232 float Rvalue = 0, Gvalue = 0, Bvalue = 0, RGgain = 0, BGgain = 0;
233 for (int i = 0; i < RK_AIQ_AWB_GRID_NUM_TOTAL; i++) {
234 Rvalue = (float)stats_ref->awb_stats_v32.blockResult[i].Rvalue;
235 Gvalue = (float)stats_ref->awb_stats_v32.blockResult[i].Gvalue;
236 Bvalue = (float)stats_ref->awb_stats_v32.blockResult[i].Bvalue;
237 RGgain = RGgain + Rvalue / Gvalue;
238 BGgain = BGgain + Bvalue / Gvalue;
239 }
240 RGgain /= RK_AIQ_AWB_GRID_NUM_TOTAL;
241 BGgain /= RK_AIQ_AWB_GRID_NUM_TOTAL;
242 printf("origin rggain_base:%0.3f, bggain_base:%0.3f\n", RGgain, BGgain);
243 }
244 rk_aiq_uapi2_sysctl_release3AStatsRef(ctx, stats_ref);
245 } else {
246 if (ret == XCAM_RETURN_NO_ERROR) {
247 printf("aiq has stopped !\n");
248 } else if (ret == XCAM_RETURN_ERROR_TIMEOUT) {
249 printf("aiq timeout!\n");
250 } else if (ret == XCAM_RETURN_ERROR_FAILED) {
251 printf("aiq failed!\n");
252 }
253 }
254 }
255 printf("SmartIr Calib Done ...... \n");
256 }
257
sample_smartIr_module(const void * arg)258 XCamReturn sample_smartIr_module(const void* arg)
259 {
260 int key = -1;
261 CLEAR();
262
263 const demo_context_t *demo_ctx = (demo_context_t *)arg;
264 const rk_aiq_sys_ctx_t* ctx;
265 if (demo_ctx->camGroup) {
266 ctx = (rk_aiq_sys_ctx_t*)(demo_ctx->camgroup_ctx);
267 } else {
268 ctx = (rk_aiq_sys_ctx_t*)(demo_ctx->aiq_ctx);
269 }
270
271 if (ctx == NULL) {
272 ERR("%s, ctx is nullptr\n", __FUNCTION__);
273 return XCAM_RETURN_ERROR_PARAM;
274 }
275
276 sample_smartIr_usage();
277
278 g_sample_smartIr_ctx.tquit = false;
279 g_sample_smartIr_ctx.started = false;
280 g_sample_smartIr_ctx.aiq_ctx = ctx;
281 g_sample_smartIr_ctx.ir_ctx = NULL;
282
283 do {
284 key = getchar();
285 while (key == '\n' || key == '\r')
286 key = getchar();
287 printf("\n");
288
289 switch (key) {
290 case 'h':
291 CLEAR();
292 sample_smartIr_usage();
293 break;
294 case 'e':
295 sample_smartIr_stop(ctx);
296 break;
297 case 's':
298 sample_smartIr_start(ctx);
299 break;
300 case 'c':
301 sample_smartIr_calib(ctx);
302 break;
303 default:
304 break;
305 }
306 } while (key != 'q' && key != 'Q');
307
308 sample_smartIr_stop(ctx);
309
310 return XCAM_RETURN_NO_ERROR;
311 }
312
313 #else
sample_print_smartIr_info(const void * arg)314 void sample_print_smartIr_info(const void* arg)
315 {
316 printf("enter SmartIr modult test!\n");
317 }
318
sample_smartIr_module(const void * arg)319 XCamReturn sample_smartIr_module(const void* arg)
320 {
321 printf("Not enabled! Add option SAMPLE_SMART_IR in makefile \n");
322 return XCAM_RETURN_NO_ERROR;
323 }
324 #endif
325