• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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