1 /*
2 *
3 * SPDX-License-Identifier: GPL-2.0
4 *
5 * Copyright (C) 2011-2018 ARM or its affiliates
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "acamera_fw.h"
21 #include "acamera_math.h"
22 #include "acamera_metering_stats_mem_config.h"
23 #include "system_stdlib.h"
24 #include "awb_manual_fsm.h"
25 #include "sbuf.h"
26
27 #include <linux/vmalloc.h>
28 #include <asm/uaccess.h>
29 #include <linux/uaccess.h>
30
31 #ifdef LOG_MODULE
32 #undef LOG_MODULE
33 #define LOG_MODULE LOG_MODULE_AWB_MANUAL
34 #endif
35
acamera_awb_statistics_data_read(AWB_fsm_t * p_fsm,uint32_t index_inp)36 static __inline uint32_t acamera_awb_statistics_data_read( AWB_fsm_t *p_fsm, uint32_t index_inp )
37 {
38 return acamera_metering_stats_mem_array_data_read( p_fsm->cmn.isp_base, index_inp + ISP_METERING_OFFSET_AWB );
39 }
40
41 //==========AWB functions (calling order: awb.scxml)=============================
42 // Handle the hardware interrupt
AWB_fsm_process_interrupt(const AWB_fsm_t * p_fsm,uint8_t irq_event)43 void AWB_fsm_process_interrupt( const AWB_fsm_t *p_fsm, uint8_t irq_event )
44 {
45 if ( acamera_fsm_util_is_irq_event_ignored( (fsm_irq_mask_t *)( &p_fsm->mask ), irq_event ) )
46 return;
47
48 switch ( irq_event ) {
49 case ACAMERA_IRQ_AWB_STATS:
50 awb_read_statistics( (AWB_fsm_t *)p_fsm ); // we know what we are doing
51 fsm_raise_event( p_fsm, event_id_awb_stats_ready );
52 break;
53 case ACAMERA_IRQ_FRAME_END:
54 awb_coeffs_write( p_fsm );
55 break;
56 }
57 }
58
59 // Write matrix coefficients
awb_coeffs_write(const AWB_fsm_t * p_fsm)60 void awb_coeffs_write( const AWB_fsm_t *p_fsm )
61 {
62 acamera_isp_ccm_coefft_wb_r_write( p_fsm->cmn.isp_base, p_fsm->awb_warming[0] );
63 acamera_isp_ccm_coefft_wb_g_write( p_fsm->cmn.isp_base, p_fsm->awb_warming[1] );
64 acamera_isp_ccm_coefft_wb_b_write( p_fsm->cmn.isp_base, p_fsm->awb_warming[2] );
65
66 LOG( LOG_INFO, "awb param applied: %u-%u-%u.", (unsigned int)p_fsm->awb_warming[0], (unsigned int)p_fsm->awb_warming[1], (unsigned int)p_fsm->awb_warming[2] );
67 }
68
awb_roi_update(AWB_fsm_ptr_t p_fsm)69 void awb_roi_update( AWB_fsm_ptr_t p_fsm )
70 {
71 uint16_t horz_zones = acamera_isp_metering_awb_nodes_used_horiz_read( p_fsm->cmn.isp_base );
72 uint16_t vert_zones = acamera_isp_metering_awb_nodes_used_vert_read( p_fsm->cmn.isp_base );
73 uint16_t x, y;
74
75 uint16_t *ptr_awb_zone_whgh_h = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_ZONE_WGHT_HOR );
76 uint16_t *ptr_awb_zone_whgh_v = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_ZONE_WGHT_VER );
77
78 uint8_t x_start = ( uint8_t )( ( ( ( p_fsm->roi >> 24 ) & 0xFF ) * horz_zones + 128 ) >> 8 );
79 uint8_t x_end = ( uint8_t )( ( ( ( p_fsm->roi >> 8 ) & 0xFF ) * horz_zones + 128 ) >> 8 );
80 uint8_t y_start = ( uint8_t )( ( ( ( p_fsm->roi >> 16 ) & 0xFF ) * vert_zones + 128 ) >> 8 );
81 uint8_t y_end = ( uint8_t )( ( ( ( p_fsm->roi >> 0 ) & 0xFF ) * vert_zones + 128 ) >> 8 );
82 uint8_t zone_size_x = x_end - x_start;
83 uint8_t zone_size_y = y_end - y_start;
84 uint32_t middle_x = zone_size_x * 256 / 2;
85 uint32_t middle_y = zone_size_y * 256 / 2;
86
87 uint32_t len_zone_wght_hor = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_ZONE_WGHT_HOR );
88 uint32_t len_zone_wght_ver = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_ZONE_WGHT_VER );
89 uint16_t scale_x = ( horz_zones - 1 ) / ( len_zone_wght_hor > 0 ? len_zone_wght_hor : 1 ) + 1;
90 uint16_t scale_y = ( vert_zones - 1 ) / ( len_zone_wght_ver > 0 ? len_zone_wght_ver : 1 ) + 1;
91
92 uint16_t gaus_center_x = ( len_zone_wght_hor * 256 / 2 ) * scale_x;
93 uint16_t gaus_center_y = ( len_zone_wght_ver * 256 / 2 ) * scale_y;
94
95
96 for ( y = 0; y < vert_zones; y++ ) {
97 uint8_t awb_coeff = 0;
98 for ( x = 0; x < horz_zones; x++ ) {
99 if ( y >= y_start && y <= y_end &&
100 x >= x_start && x <= x_end ) {
101
102 uint8_t index_y = ( y - y_start );
103 uint8_t index_x = ( x - x_start );
104 int32_t distance_x = ( index_x * 256 + 128 ) - middle_x;
105 int32_t distance_y = ( index_y * 256 + 128 ) - middle_y;
106 uint32_t coeff_x;
107 uint32_t coeff_y;
108
109 if ( ( x == x_end && x_start != x_end ) ||
110 ( y == y_end && y_start != y_end ) ) {
111 awb_coeff = 0;
112 } else {
113 coeff_x = ( gaus_center_x + distance_x ) / 256;
114 if ( distance_x > 0 && ( distance_x & 0x80 ) )
115 coeff_x--;
116 coeff_y = ( gaus_center_y + distance_y ) / 256;
117 if ( distance_y > 0 && ( distance_y & 0x80 ) )
118 coeff_y--;
119
120 coeff_x = ptr_awb_zone_whgh_h[coeff_x / scale_x];
121 coeff_y = ptr_awb_zone_whgh_v[coeff_y / scale_y];
122
123 awb_coeff = ( coeff_x * coeff_y ) >> 4;
124 if ( awb_coeff > 1 )
125 awb_coeff--;
126 }
127 } else {
128 awb_coeff = 0;
129 }
130 acamera_isp_metering_awb_zones_weight_write( p_fsm->cmn.isp_base, y * vert_zones + x, awb_coeff );
131 }
132 }
133 }
134
awb_set_zone_weight(AWB_fsm_ptr_t p_fsm,void * u_wg_ptr)135 int awb_set_zone_weight(AWB_fsm_ptr_t p_fsm, void *u_wg_ptr)
136 {
137 int ret = -1;
138 unsigned long awb_wg_size = 0;
139 uint8_t *awb_wg = NULL;
140 int x = 0;
141 int y = 0;
142 uint8_t awb_coeff = 0;
143 uint32_t idx = 0;
144
145 if (p_fsm == NULL || u_wg_ptr == NULL) {
146 LOG(LOG_ERR, "Error invalid input param");
147 return ret;
148 }
149
150 awb_wg_size = ISP_METERING_ZONES_AWB_H * ISP_METERING_ZONES_AWB_V;
151 awb_wg = vmalloc(awb_wg_size);
152 if (awb_wg == NULL) {
153 LOG(LOG_ERR, "Failed to malloc mem");
154 return ret;
155 }
156
157 memset(awb_wg, 0, awb_wg_size);
158
159 if (copy_from_user(awb_wg, u_wg_ptr, awb_wg_size)) {
160 vfree(awb_wg);
161 LOG(LOG_ERR, "Failed to copy awb weight");
162 return ret;
163 }
164
165 for (y = 0; y < ISP_METERING_ZONES_AWB_V; y++) {
166 for (x = 0; x < ISP_METERING_ZONES_AWB_H; x++) {
167 idx = y * ISP_METERING_ZONES_AWB_H + x;
168 awb_coeff = awb_wg[idx];
169 acamera_isp_metering_awb_zones_weight_write(
170 p_fsm->cmn.isp_base, idx, awb_coeff);
171 }
172 }
173
174 vfree(awb_wg);
175
176 return 0;
177 }
178
179 // Initalisation code
awb_init(AWB_fsm_t * p_fsm)180 void awb_init( AWB_fsm_t *p_fsm )
181 {
182 uint32_t width;
183 uint32_t height;
184 // Initial AWB (rg,bg) is the identity
185 p_fsm->rg_coef = 0x100;
186 p_fsm->bg_coef = 0x100;
187
188 // Set the default awb values
189 if ( MAX_AWB_ZONES < acamera_isp_metering_awb_nodes_used_horiz_read( p_fsm->cmn.isp_base ) * acamera_isp_metering_awb_nodes_used_vert_read( p_fsm->cmn.isp_base ) ) {
190 LOG( LOG_CRIT, "MAX_AWB_ZONES is less than hardware reported zones" );
191 }
192
193 p_fsm->wb_log2[0] = 252071;
194 p_fsm->wb_log2[1] = 87;
195 p_fsm->wb_log2[2] = 87;
196 p_fsm->wb_log2[3] = 180394;
197 awb_coeffs_write( p_fsm );
198
199 acamera_isp_white_balance_gain_00_write( p_fsm->cmn.isp_base, p_fsm->wb[0]);
200 acamera_isp_white_balance_gain_01_write( p_fsm->cmn.isp_base, p_fsm->wb[1]);
201 acamera_isp_white_balance_gain_10_write( p_fsm->cmn.isp_base, p_fsm->wb[2]);
202 acamera_isp_white_balance_gain_11_write( p_fsm->cmn.isp_base, p_fsm->wb[3]);
203
204 width = acamera_isp_top_active_width_read( p_fsm->cmn.isp_base );
205 height = acamera_isp_top_active_height_read( p_fsm->cmn.isp_base );
206
207 if ( p_fsm->curr_AWB_ZONES != 0 ) {
208 p_fsm->valid_threshold = ( width * height / ( 10 * p_fsm->curr_AWB_ZONES ) ); // division by zero is checked
209 } else {
210 p_fsm->valid_threshold = 0;
211 LOG( LOG_CRIT, "AVOIDED DIVISION BY ZERO" );
212 }
213
214 p_fsm->awb_warming[0] = (int32_t)_GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_WARMING_LS_D50 )[0];
215 p_fsm->awb_warming[1] = (int32_t)_GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_WARMING_LS_D50 )[1];
216 p_fsm->awb_warming[2] = (int32_t)_GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_WARMING_LS_D50 )[2];
217
218 acamera_isp_ccm_coefft_wb_r_write( p_fsm->cmn.isp_base, p_fsm->awb_warming[0] );
219 acamera_isp_ccm_coefft_wb_g_write( p_fsm->cmn.isp_base, p_fsm->awb_warming[1] );
220 acamera_isp_ccm_coefft_wb_b_write( p_fsm->cmn.isp_base, p_fsm->awb_warming[2] );
221
222 // Set the min/max temperatures and their gains:
223 if ( ( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_COLOR_TEMP )[0] != 0 ) && ( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_COLOR_TEMP )[_GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_COLOR_TEMP ) - 1] != 0 ) && ( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_RG_POS_CALC )[0] != 0 ) && ( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_BG_POS_CALC )[0] != 0 ) && ( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_RG_POS_CALC )[_GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_RG_POS_CALC ) - 1] != 0 ) && ( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_BG_POS_CALC )[_GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_BG_POS_CALC ) - 1] != 0 ) ) {
224 p_fsm->min_temp = 1000000 / _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_COLOR_TEMP )[_GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_COLOR_TEMP ) - 1]; // division by zero is checked
225 p_fsm->max_temp = 1000000 / _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_COLOR_TEMP )[0]; // division by zero is checked
226 p_fsm->max_temp_rg = U16_MAX / _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_RG_POS_CALC )[0]; // division by zero is checked
227 p_fsm->max_temp_bg = U16_MAX / _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_BG_POS_CALC )[0]; // division by zero is checked
228 p_fsm->min_temp_rg = U16_MAX / _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_RG_POS_CALC )[_GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_RG_POS_CALC ) - 1]; // division by zero is checked
229 p_fsm->min_temp_bg = U16_MAX / _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_BG_POS_CALC )[_GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CT_BG_POS_CALC ) - 1]; // division by zero is checked
230 } else {
231 LOG( LOG_CRIT, "AVOIDED DIVISION BY ZERO" );
232 }
233
234 awb_roi_update( p_fsm );
235 }
236
237 // Set the 3x3 colour matrix to the identity matrix
awb_set_identity(AWB_fsm_t * p_fsm)238 void awb_set_identity( AWB_fsm_t *p_fsm )
239 {
240 int i;
241
242 for ( i = 0; i < 9; ++i ) {
243 p_fsm->color_wb_matrix[i] = 0;
244 }
245 p_fsm->color_wb_matrix[0] = p_fsm->color_wb_matrix[4] = p_fsm->color_wb_matrix[8] = 0x100;
246 }
247
248 // Read the statistics from hardware
awb_read_statistics(AWB_fsm_t * p_fsm)249 void awb_read_statistics( AWB_fsm_t *p_fsm )
250 {
251 uint32_t _metering_lut_entry;
252 uint16_t irg;
253 uint16_t ibg;
254 sbuf_awb_t *p_sbuf_awb_stats = NULL;
255 struct sbuf_item sbuf;
256 int fw_id = p_fsm->cmn.ctx_id;
257
258 // Only selected number of zones will contribute
259 uint16_t _i;
260
261 p_fsm->sum = 0;
262
263 memset( &sbuf, 0, sizeof( sbuf ) );
264 sbuf.buf_type = SBUF_TYPE_AWB;
265 sbuf.buf_status = SBUF_STATUS_DATA_EMPTY;
266
267 if ( sbuf_get_item( fw_id, &sbuf ) ) {
268 LOG( LOG_ERR, "Error: Failed to get sbuf, return." );
269 return;
270 }
271
272 p_sbuf_awb_stats = (sbuf_awb_t *)sbuf.buf_base;
273 LOG( LOG_DEBUG, "Get sbuf ok, idx: %u, status: %u, addr: %p.", sbuf.buf_idx, sbuf.buf_status, sbuf.buf_base );
274
275 fsm_param_mon_alg_flow_t awb_flow;
276
277 awb_flow.frame_id_tracking = acamera_fsm_util_get_cur_frame_id( &p_fsm->cmn );
278 p_sbuf_awb_stats->frame_id = awb_flow.frame_id_tracking;
279
280 // Read out the per zone statistics
281 p_fsm->curr_AWB_ZONES = acamera_isp_metering_awb_nodes_used_horiz_read( p_fsm->cmn.isp_base ) *
282 acamera_isp_metering_awb_nodes_used_vert_read( p_fsm->cmn.isp_base );
283
284 for ( _i = 0; _i < p_fsm->curr_AWB_ZONES; ++_i ) {
285 _metering_lut_entry = acamera_awb_statistics_data_read( p_fsm, _i * 2 );
286 //What we get from HW is G/R.
287 //It is also programmable in the latest HW.AWB_STATS_MODE=0-->G/R and AWB_STATS_MODE=1-->R/G
288 //rg_coef is actually R_gain appiled to R Pixels.Since we get (G*G_gain)/(R*R_gain) from HW,we multiply by the gain rg_coef to negate its effect.
289 irg = ( _metering_lut_entry & 0xfff );
290 ibg = ( ( _metering_lut_entry >> 16 ) & 0xfff );
291
292 irg = ( irg * ( p_fsm->rg_coef ) ) >> 8;
293 ibg = ( ibg * ( p_fsm->bg_coef ) ) >> 8;
294 irg = ( irg == 0 ) ? 1 : irg;
295 ibg = ( ibg == 0 ) ? 1 : ibg;
296
297 p_sbuf_awb_stats->stats_data[_i].rg = U16_MAX / irg;
298 p_sbuf_awb_stats->stats_data[_i].bg = U16_MAX / ibg;
299 p_sbuf_awb_stats->stats_data[_i].sum = acamera_awb_statistics_data_read( p_fsm, _i * 2 + 1 );
300 p_fsm->sum += p_sbuf_awb_stats->stats_data[_i].sum;
301 }
302 p_sbuf_awb_stats->curr_AWB_ZONES = p_fsm->curr_AWB_ZONES;
303
304 /* read done, set the buffer back for future using */
305 sbuf.buf_status = SBUF_STATUS_DATA_DONE;
306
307 if ( sbuf_set_item( fw_id, &sbuf ) ) {
308 LOG( LOG_ERR, "Error: Failed to set sbuf, return." );
309 return;
310 }
311 LOG( LOG_DEBUG, "Set sbuf ok, idx: %u, status: %u, addr: %p.", sbuf.buf_idx, sbuf.buf_status, sbuf.buf_base );
312
313 awb_flow.frame_id_current = acamera_fsm_util_get_cur_frame_id( &p_fsm->cmn );
314 awb_flow.flow_state = MON_ALG_FLOW_STATE_INPUT_READY;
315 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_MON_AWB_FLOW, &awb_flow, sizeof( awb_flow ) );
316 }
317
318 // For CCM switching
awb_update_ccm(AWB_fsm_t * p_fsm)319 void awb_update_ccm( AWB_fsm_t *p_fsm )
320 {
321 int32_t total_gain = 0;
322 int high_gain = 0;
323
324 LOG( LOG_DEBUG, "p_high: %d, light_source_candidate: %d, temperature_detected: %d.\n",
325 p_fsm->p_high,
326 p_fsm->light_source_candidate,
327 p_fsm->temperature_detected );
328
329 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_CMOS_TOTAL_GAIN, NULL, 0, &total_gain, sizeof( total_gain ) );
330
331 high_gain = ( total_gain >> ( LOG2_GAIN_SHIFT - 8 ) ) >= _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CCM_ONE_GAIN_THRESHOLD )[0];
332
333 fsm_param_ccm_info_t ccm_info;
334 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_CCM_INFO, NULL, 0, &ccm_info, sizeof( ccm_info ) );
335
336 if ( p_fsm->p_high > 60 ) {
337 ++p_fsm->detect_light_source_frames_count;
338 if ( p_fsm->detect_light_source_frames_count >= p_fsm->switch_light_source_detect_frames_quantity ) {
339 #ifdef AWB_PRINT_DEBUG
340 if ( ccm_info.light_source != AWB_LIGHT_SOURCE_D50 ) {
341 LOG( LOG_DEBUG, "Light source is changed\n" );
342 LOG( LOG_DEBUG, "p_high=%d, using AWB_LIGHT_SOURCE_D50\n", p_fsm->p_high );
343 }
344 #endif
345
346 ccm_info.light_source_previous = ccm_info.light_source;
347 ccm_info.light_source = p_fsm->light_source_candidate;
348 ccm_info.light_source_ccm_previous = ccm_info.light_source_ccm;
349 ccm_info.light_source_ccm = high_gain ? AWB_LIGHT_SOURCE_UNKNOWN : p_fsm->light_source_candidate; // for low light set ccm = I
350 ccm_info.light_source_change_frames = p_fsm->switch_light_source_change_frames_quantity;
351 ccm_info.light_source_change_frames_left = p_fsm->switch_light_source_change_frames_quantity;
352
353 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_CCM_INFO, &ccm_info, sizeof( ccm_info ) );
354 }
355
356 } else if ( p_fsm->light_source_detected == p_fsm->light_source_candidate ) {
357 if ( ( p_fsm->light_source_candidate != ccm_info.light_source ) || ( high_gain && ccm_info.light_source_ccm != AWB_LIGHT_SOURCE_UNKNOWN ) || ( !high_gain && ccm_info.light_source_ccm == AWB_LIGHT_SOURCE_UNKNOWN ) ) {
358 ++p_fsm->detect_light_source_frames_count;
359 if ( p_fsm->detect_light_source_frames_count >= p_fsm->switch_light_source_detect_frames_quantity && !ccm_info.light_source_change_frames_left ) {
360 ccm_info.light_source_previous = ccm_info.light_source;
361 ccm_info.light_source = p_fsm->light_source_candidate;
362 ccm_info.light_source_ccm_previous = ccm_info.light_source_ccm;
363 ccm_info.light_source_ccm = high_gain ? AWB_LIGHT_SOURCE_UNKNOWN : p_fsm->light_source_candidate; // for low light set ccm = I
364 ccm_info.light_source_change_frames = p_fsm->switch_light_source_change_frames_quantity;
365 ccm_info.light_source_change_frames_left = p_fsm->switch_light_source_change_frames_quantity;
366
367 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_CCM_INFO, &ccm_info, sizeof( ccm_info ) );
368 #ifdef AWB_PRINT_DEBUG
369 // These are rarer so can print wherever they are fired (i.e. not dependent on ittcount)
370 LOG( LOG_DEBUG, "Light source is changed\n" );
371 if ( ccm_info.light_source == AWB_LIGHT_SOURCE_A )
372 LOG( LOG_DEBUG, "AWB_LIGHT_SOURCE_A\n" );
373 if ( ccm_info.light_source == AWB_LIGHT_SOURCE_D40 )
374 LOG( LOG_DEBUG, "AWB_LIGHT_SOURCE_D40\n" );
375 if ( ccm_info.light_source == AWB_LIGHT_SOURCE_D50 )
376 LOG( LOG_DEBUG, "AWB_LIGHT_SOURCE_D50\n" );
377 #endif
378 }
379 }
380 } else {
381 p_fsm->detect_light_source_frames_count = 0;
382 }
383 p_fsm->light_source_detected = p_fsm->light_source_candidate;
384 }
385
386 // Perform normalisation
awb_normalise(AWB_fsm_t * p_fsm)387 void awb_normalise( AWB_fsm_t *p_fsm )
388 {
389 int32_t wb[4];
390
391 wb[0] = acamera_log2_fixed_to_fixed( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_STATIC_WB )[0], 8, LOG2_GAIN_SHIFT );
392 wb[1] = acamera_log2_fixed_to_fixed( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_STATIC_WB )[1], 8, LOG2_GAIN_SHIFT );
393 wb[2] = acamera_log2_fixed_to_fixed( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_STATIC_WB )[2], 8, LOG2_GAIN_SHIFT );
394 wb[3] = acamera_log2_fixed_to_fixed( _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_STATIC_WB )[3], 8, LOG2_GAIN_SHIFT );
395
396 {
397 /* For both auto mode and manual mode, we use the same variables to save the red/blue gains */
398 wb[0] += acamera_log2_fixed_to_fixed( ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_awb_red_gain, 8, LOG2_GAIN_SHIFT );
399 wb[3] += acamera_log2_fixed_to_fixed( ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_awb_blue_gain, 8, LOG2_GAIN_SHIFT );
400 p_fsm->rg_coef = ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_awb_red_gain;
401 p_fsm->bg_coef = ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_awb_blue_gain;
402 }
403
404 {
405 int i;
406 int32_t min_wb = wb[0];
407 int32_t diff;
408
409 for ( i = 1; i < 4; ++i ) {
410 int32_t _wb = wb[i];
411 if ( min_wb > _wb ) {
412 min_wb = _wb;
413 }
414 }
415
416 fsm_param_sensor_info_t sensor_info;
417 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_SENSOR_INFO, NULL, 0, &sensor_info, sizeof( sensor_info ) );
418
419 diff = ( ISP_INPUT_BITS << LOG2_GAIN_SHIFT ) - acamera_log2_fixed_to_fixed( ( 1 << ISP_INPUT_BITS ) - sensor_info.black_level, 0, LOG2_GAIN_SHIFT ) - min_wb;
420 for ( i = 0; i < 4; ++i ) {
421 int32_t _wb = wb[i] + diff;
422 p_fsm->wb_log2[i] = _wb;
423 }
424 }
425 }
426
awb_set_new_param(AWB_fsm_ptr_t p_fsm,sbuf_awb_t * p_sbuf_awb)427 void awb_set_new_param( AWB_fsm_ptr_t p_fsm, sbuf_awb_t *p_sbuf_awb )
428 {
429 if ( p_sbuf_awb->frame_id == p_fsm->cur_result_gain_frame_id ) {
430 LOG( LOG_ERR, "Error: Same frame used twice, frame_id: %u.", p_sbuf_awb->frame_id );
431 return;
432 }
433
434 status_info_param_t *p_status_info = (status_info_param_t *)_GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_STATUS_INFO );
435 p_status_info->awb_info.mix_light_contrast = p_sbuf_awb->mix_light_contrast;
436
437 ACAMERA_FSM2CTX_PTR( p_fsm )
438 ->stab.global_awb_red_gain = p_sbuf_awb->awb_red_gain;
439 ACAMERA_FSM2CTX_PTR( p_fsm )
440 ->stab.global_awb_blue_gain = p_sbuf_awb->awb_blue_gain;
441
442 p_fsm->temperature_detected = p_sbuf_awb->temperature_detected;
443 p_fsm->light_source_candidate = p_sbuf_awb->light_source_candidate;
444 p_fsm->p_high = p_sbuf_awb->p_high;
445 system_memcpy( p_fsm->awb_warming, p_sbuf_awb->awb_warming, sizeof( p_fsm->awb_warming ) );
446
447 p_fsm->cur_result_gain_frame_id = p_sbuf_awb->frame_id;
448
449 if ( p_fsm->cur_result_gain_frame_id && ( p_fsm->pre_result_gain_frame_id != p_fsm->cur_result_gain_frame_id ) ) {
450 fsm_param_mon_alg_flow_t awb_flow;
451
452 p_fsm->pre_result_gain_frame_id = p_fsm->cur_result_gain_frame_id;
453
454 awb_flow.frame_id_tracking = p_fsm->cur_result_gain_frame_id;
455 awb_flow.frame_id_current = acamera_fsm_util_get_cur_frame_id( &p_fsm->cmn );
456 awb_flow.flow_state = MON_ALG_FLOW_STATE_OUTPUT_READY;
457 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_MON_AWB_FLOW, &awb_flow, sizeof( awb_flow ) );
458 }
459
460 fsm_raise_event( p_fsm, event_id_awb_result_ready );
461 }
462