diff --git a/drivers/video/isx012.c b/drivers/video/isx012.c index 0d42973d04..1c97b3023e 100644 --- a/drivers/video/isx012.c +++ b/drivers/video/isx012.c @@ -152,6 +152,11 @@ #define CLIP_SIZE_UNIT (8) #define RESCALE_FOR_CLIP(v, a, b) (((v) * (a)) / (b)) +/* The number of whole image splits for spot position decision. */ + +#define ISX012_SPOT_POSITION_SPLIT_NUM_X (9) +#define ISX012_SPOT_POSITION_SPLIT_NUM_Y (7) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -1902,6 +1907,15 @@ static int isx012_get_supported_value(FAR struct imgsensor_s *sensor, break; + case IMGSENSOR_ID_SPOT_POSITION: + value->type = IMGSENSOR_CTRL_TYPE_INTEGER; + range->minimum = ISX012_MIN_SPOTPOS; + range->maximum = ISX012_MAX_SPOTPOS; + range->step = ISX012_STEP_SPOTPOS; + range->default_value = ISX012_DEF_SPOTPOS; + + break; + case IMGSENSOR_ID_AUTO_N_PRESET_WB: value->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU; discrete->nr_values = ARRAY_NENTRIES(g_isx012_presetwb_actual); @@ -1981,6 +1995,70 @@ static int isx012_get_supported_value(FAR struct imgsensor_s *sensor, return ret; } +static void get_current_framesize(FAR struct isx012_dev_s *priv, + FAR uint16_t *w, + FAR uint16_t *h) +{ + uint16_t w_addr = HSIZE_MONI; + uint16_t h_addr = VSIZE_MONI; + + switch (priv->mode) + { + case REGVAL_MODESEL_MON: + w_addr = HSIZE_MONI; + h_addr = VSIZE_MONI; + break; + + case REGVAL_MODESEL_MOV: + w_addr = HSIZE_MOVIE; + h_addr = VSIZE_MOVIE; + break; + + case REGVAL_MODESEL_CAP: + w_addr = HSIZE_CAP; + h_addr = VSIZE_CAP; + break; + + default: + + /* It does not come here due to register specification. */ + + break; + } + + *w = isx012_getreg(priv, w_addr, 2); + *h = isx012_getreg(priv, h_addr, 2); +} + +static uint32_t restore_spot_position(uint8_t regval, + uint16_t w, + uint16_t split) +{ + return ((regval * w) / split + (w / split) / 2); +} + +static int32_t get_spot_position(FAR struct isx012_dev_s *priv) +{ + uint16_t regval; + uint16_t reg_x; + uint16_t reg_y; + uint32_t x; + uint32_t y; + uint16_t w; + uint16_t h; + + regval = isx012_getreg(priv, SPOT_FRM_NUM, 1); + reg_x = regval % ISX012_SPOT_POSITION_SPLIT_NUM_X; + reg_y = regval / ISX012_SPOT_POSITION_SPLIT_NUM_X; + + get_current_framesize(priv, &w, &h); + + x = restore_spot_position(reg_x, w, ISX012_SPOT_POSITION_SPLIT_NUM_X); + y = restore_spot_position(reg_y, h, ISX012_SPOT_POSITION_SPLIT_NUM_Y); + + return (int32_t)((x << 16) | y); +} + static int isx012_get_value(FAR struct imgsensor_s *sensor, uint32_t id, uint32_t size, FAR imgsensor_value_t *value) @@ -2245,6 +2323,10 @@ static int isx012_get_value(FAR struct imgsensor_s *sensor, break; + case IMGSENSOR_ID_SPOT_POSITION: + value->value32 = get_spot_position(priv); + break; + case IMGSENSOR_ID_3A_PARAMETER: if (value->p_u16 == NULL) { @@ -2356,6 +2438,31 @@ static int set_clip(uint32_t size, return OK; } +static int set_spot_position(FAR struct isx012_dev_s *priv, int32_t val) +{ + uint16_t w; + uint16_t h; + uint16_t x = (uint16_t)(val >> 16); + uint16_t y = (uint16_t)(val & 0xffff); + uint8_t reg_x; + uint8_t reg_y; + uint8_t reg; + + get_current_framesize(priv, &w, &h); + + if ((x >= w) || (y >= h)) + { + return -EINVAL; + } + + reg_x = (x * ISX012_SPOT_POSITION_SPLIT_NUM_X) / w; + reg_y = (y * ISX012_SPOT_POSITION_SPLIT_NUM_Y) / h; + + reg = reg_y * ISX012_SPOT_POSITION_SPLIT_NUM_X + reg_x; + + return isx012_putreg(priv, SPOT_FRM_NUM, reg, 1); +} + static int isx012_set_value(FAR struct imgsensor_s *sensor, uint32_t id, uint32_t size, imgsensor_value_t value) @@ -2854,6 +2961,19 @@ static int isx012_set_value(FAR struct imgsensor_s *sensor, break; + case IMGSENSOR_ID_SPOT_POSITION: + ret = VALIDATE_VALUE(value.value32, + ISX012_MIN_SPOTPOS, + ISX012_MAX_SPOTPOS, + ISX012_STEP_SPOTPOS); + if (ret != OK) + { + break; + } + + ret = set_spot_position(priv, value.value32); + break; + case IMGSENSOR_ID_AUTO_N_PRESET_WB: for (cnt = 0; cnt < ARRAY_NENTRIES(g_isx012_presetwb_actual); diff --git a/drivers/video/isx012_range.h b/drivers/video/isx012_range.h index 698ba9d8d2..144687370a 100644 --- a/drivers/video/isx012_range.h +++ b/drivers/video/isx012_range.h @@ -222,6 +222,16 @@ #define ISX012_REG_PHOTOMETRY AE_SUB_SN1 #define ISX012_SIZE_PHOTOMETRY (1) +/* Definition for control spot position */ + +#define ISX012_TYPE_SPOTPOS V4L2_CTRL_TYPE_INTEGER +#define ISX012_DEF_SPOTPOS (0x051003cc) +#define ISX012_MIN_SPOTPOS (0) +#define ISX012_MAX_SPOTPOS (0x0a200798) +#define ISX012_STEP_SPOTPOS (1) +#define ISX012_REG_SPOTPOS SPOT_FRM_NUM +#define ISX012_SIZE_SPOTPOS (1) + /* Definition for control zoom */ #define ISX012_TYPE_ZOOM V4L2_CTRL_TYPE_U16FIXEDPOINT_Q8 diff --git a/drivers/video/isx012_reg.h b/drivers/video/isx012_reg.h index a30c934607..2c4e41d093 100644 --- a/drivers/video/isx012_reg.h +++ b/drivers/video/isx012_reg.h @@ -667,6 +667,7 @@ #define AE_INIT_MASK_CNT (AE_BASE+0x002B) #define AESPEED_INIT (AE_BASE+0x0031) #define AESPEED_FAST (AE_BASE+0x0032) +#define SPOT_FRM_NUM (AE_BASE+0x0033) #define FASTMOVE_TIMEOUT (AE_BASE+0x003D) #define AE_START_LEVEL (AE_BASE+0x0040) diff --git a/drivers/video/isx019.c b/drivers/video/isx019.c index 8d7d8ad256..9fea377e13 100644 --- a/drivers/video/isx019.c +++ b/drivers/video/isx019.c @@ -154,6 +154,16 @@ #define VTIME_PER_FRAME (30518) #define INTERVAL_PER_FRAME (33333) +/* ISX019 image sensor output frame size. */ + +#define ISX019_WIDTH (1280) +#define ISX019_HEIGHT (960) + +/* The number of whole image splits for spot position decision. */ + +#define ISX019_SPOT_POSITION_SPLIT_NUM_X (9) +#define ISX019_SPOT_POSITION_SPLIT_NUM_Y (7) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -179,6 +189,7 @@ struct isx019_default_value_s int32_t iso; int32_t iso_auto; int32_t meter; + int32_t spot_pos; int32_t threealock; int32_t threeastatus; int32_t jpgquality; @@ -1238,6 +1249,7 @@ static void store_default_value(FAR isx019_dev_t *priv) def->iso = get_value32(priv, IMGSENSOR_ID_ISO_SENSITIVITY); def->iso_auto = get_value32(priv, IMGSENSOR_ID_ISO_SENSITIVITY_AUTO); def->meter = get_value32(priv, IMGSENSOR_ID_EXPOSURE_METERING); + def->spot_pos = get_value32(priv, IMGSENSOR_ID_SPOT_POSITION); def->threealock = get_value32(priv, IMGSENSOR_ID_3A_LOCK); def->threeastatus = get_value32(priv, IMGSENSOR_ID_3A_STATUS); def->jpgquality = get_value32(priv, IMGSENSOR_ID_JPEG_QUALITY); @@ -1888,6 +1900,12 @@ static int isx019_get_supported_value(FAR struct imgsensor_s *sensor, STEP_METER, def->meter); break; + case IMGSENSOR_ID_SPOT_POSITION: + val->type = IMGSENSOR_CTRL_TYPE_INTEGER; + SET_RANGE(val->u.range, MIN_SPOTPOS, MAX_SPOTPOS, + STEP_SPOTPOS, def->spot_pos); + break; + case IMGSENSOR_ID_3A_LOCK: val->type = IMGSENSOR_CTRL_TYPE_BITMASK; SET_RANGE(val->u.range, MIN_3ALOCK, MAX_3ALOCK, @@ -2364,6 +2382,158 @@ static int set_meter(FAR isx019_dev_t *priv, return OK; } +static void get_current_framesize(FAR isx019_dev_t *priv, + FAR uint16_t *w, FAR uint16_t *h) +{ + uint8_t frmsz; + + DEBUGASSERT(w && h); + + fpga_i2c_read(priv, FPGA_FORMAT_AND_SCALE, &frmsz, 1); + + switch (frmsz & 0xf0) + { + case FPGA_SCALE_1280_960: + *w = 1280; + *h = 960; + break; + + case FPGA_SCALE_640_480: + *w = 640; + *h = 480; + break; + + case FPGA_SCALE_320_240: + *w = 320; + *h = 240; + break; + + case FPGA_SCALE_160_120: + *w = 160; + *h = 120; + break; + + default: + + /* It may not come here due to register specification */ + + break; + } +} + +static void get_current_clip_setting(FAR isx019_dev_t *priv, + FAR uint16_t *w, + FAR uint16_t *h, + FAR uint16_t *offset_x, + FAR uint16_t *offset_y) +{ + uint8_t sz; + uint8_t top; + uint8_t left; + + fpga_i2c_read(priv, FPGA_CLIP_SIZE, &sz, 1); + fpga_i2c_read(priv, FPGA_CLIP_TOP, &top, 1); + fpga_i2c_read(priv, FPGA_CLIP_LEFT, &left, 1); + + *offset_x = left * FPGA_CLIP_UNIT; + *offset_y = top * FPGA_CLIP_UNIT; + + switch (sz) + { + case FPGA_CLIP_NON: + *w = 0; + *h = 0; + *offset_x = 0; + *offset_y = 0; + break; + + case FPGA_CLIP_1280_720: + *w = 1280; + *h = 720; + break; + + case FPGA_CLIP_640_360: + *w = 640; + *h = 360; + break; + + default: + + /* It may not come here due to register specification */ + + break; + } +} + +static int calc_spot_position_regval(uint16_t val, + uint16_t basis, + uint16_t sz, + uint16_t offset, + int split) +{ + int ret; + int ratio; + + /* Change basis from `sz` to `basis` about `val` and `offset`. */ + + ratio = basis / sz; + ret = val * ratio; + ret += (offset * FPGA_CLIP_UNIT * ratio); + + return (ret * split) / basis; +} + +static int set_spot_position(FAR isx019_dev_t *priv, + imgsensor_value_t val) +{ + uint8_t regval; + uint8_t reg_x; + uint8_t reg_y; + uint16_t w; + uint16_t h; + uint16_t clip_w; + uint16_t clip_h; + uint16_t offset_x; + uint16_t offset_y; + uint16_t x = (uint16_t)(val.value32 >> 16); + uint16_t y = (uint16_t)(val.value32 & 0xffff); + int split; + + /* Spot position of ISX019 is divided into 9x7 sections. + * - Horizontal direction is devided into 9 sections. + * - Vertical direction is divided into 7 sections. + * The register value 0 means left top. + * The register value 62 means right bottom. + * Then, the following ISX019 board flow. + * - image sensor output the 1280x960 image + * - FPGA scale + * - FPGA clipping + */ + + get_current_framesize(priv, &w, &h); + if ((x >= w) || (y >= h)) + { + return -EINVAL; + } + + get_current_clip_setting(priv, &clip_w, &clip_h, &offset_x, &offset_y); + if ((clip_w != 0) && (clip_h != 0)) + { + if ((x >= clip_w) || (y >= clip_h)) + { + return -EINVAL; + } + } + + split = ISX019_SPOT_POSITION_SPLIT_NUM_X; + reg_x = calc_spot_position_regval(x, 1280, w, offset_x, split); + split = ISX019_SPOT_POSITION_SPLIT_NUM_Y; + reg_y = calc_spot_position_regval(y, 960, h, offset_y, split); + + regval = reg_y * ISX019_SPOT_POSITION_SPLIT_NUM_X + reg_x; + return isx019_i2c_write(priv, CAT_CATAE, SPOT_FRM_NUM, ®val, 1); +} + static int set_3alock(FAR isx019_dev_t *priv, imgsensor_value_t val) { @@ -2783,6 +2953,10 @@ static setvalue_t set_value_func(uint32_t id) func = set_meter; break; + case IMGSENSOR_ID_SPOT_POSITION: + func = set_spot_position; + break; + case IMGSENSOR_ID_3A_LOCK: func = set_3alock; break; @@ -2972,6 +3146,83 @@ static int get_meter(FAR isx019_dev_t *priv, return OK; } +static uint32_t restore_spot_position(uint16_t regval, + uint16_t basis, + uint16_t sz, + uint16_t clip_sz, + uint16_t offset, + uint16_t split) +{ + uint16_t ret; + uint16_t unit; + uint16_t border; + + /* First, convert register value to coordinate value. */ + + unit = basis / split; + + ret = (regval * unit) + (unit / 2); + + /* Second, consider the ratio between basis size and frame size. */ + + ret = ret * sz / basis; + + /* Third, consider offset value of clip setting. */ + + if (ret > offset) + { + ret = ret - offset; + } + else + { + ret = 0; + } + + /* If the coordinate protrudes from the frame, + * regard it as the boader of the frame. + */ + + border = (clip_sz != 0) ? (clip_sz - 1) : (sz - 1); + if (ret > border) + { + ret = border; + } + + return ret; +} + +static int get_spot_position(FAR isx019_dev_t *priv, + FAR imgsensor_value_t *val) +{ + uint8_t regval; + uint8_t regx; + uint8_t regy; + uint16_t w; + uint16_t h; + uint32_t x; + uint32_t y; + uint16_t clip_w; + uint16_t clip_h; + uint16_t offset_x; + uint16_t offset_y; + int split; + + isx019_i2c_read(priv, CAT_CATAE, SPOT_FRM_NUM, ®val, 1); + + regx = regval % ISX019_SPOT_POSITION_SPLIT_NUM_X; + regy = regval / ISX019_SPOT_POSITION_SPLIT_NUM_X; + + get_current_framesize(priv, &w, &h); + get_current_clip_setting(priv, &clip_w, &clip_h, &offset_x, &offset_y); + split = ISX019_SPOT_POSITION_SPLIT_NUM_X; + x = restore_spot_position(regx, ISX019_WIDTH, w, clip_w, offset_x, split); + split = ISX019_SPOT_POSITION_SPLIT_NUM_Y; + y = restore_spot_position(regy, ISX019_HEIGHT, h, clip_h, offset_y, split); + + val->value32 = (int32_t)((x << 16) | y); + return OK; +} + static int get_3alock(FAR isx019_dev_t *priv, FAR imgsensor_value_t *val) { @@ -3204,6 +3455,10 @@ static getvalue_t get_value_func(uint32_t id) func = get_meter; break; + case IMGSENSOR_ID_SPOT_POSITION: + func = get_spot_position; + break; + case IMGSENSOR_ID_3A_LOCK: func = get_3alock; break; diff --git a/drivers/video/isx019_range.h b/drivers/video/isx019_range.h index 4a3d6d143f..35365a148e 100644 --- a/drivers/video/isx019_range.h +++ b/drivers/video/isx019_range.h @@ -92,6 +92,10 @@ #define MAX_METER (3) #define STEP_METER (1) +#define MIN_SPOTPOS (0x00000000) +#define MAX_SPOTPOS (0x050003c0) +#define STEP_SPOTPOS (1) + #define MIN_PAN (-32) #define MAX_PAN (32) #define STEP_PAN (1) diff --git a/drivers/video/isx019_reg.h b/drivers/video/isx019_reg.h index 71aead7cbd..d6e9af6589 100644 --- a/drivers/video/isx019_reg.h +++ b/drivers/video/isx019_reg.h @@ -236,6 +236,7 @@ /* For CAT_CATAE */ #define AEMODE (0x0000) +#define SPOT_FRM_NUM (0x0003) #define SHT_PRIMODE (0x0008) #define GAIN_PRIMODE (0x000c) diff --git a/drivers/video/video.c b/drivers/video/video.c index 4c8ee4c6a3..a2ebc57b69 100644 --- a/drivers/video/video.c +++ b/drivers/video/video.c @@ -171,6 +171,7 @@ struct video_scene_params_s enum v4l2_iso_sensitivity_auto_type iso_auto; int32_t iso; enum v4l2_exposure_metering meter; + int32_t spot_pos; int32_t threea_lock; enum v4l2_flash_led_mode led; int32_t jpeg_quality; @@ -409,6 +410,7 @@ static const video_parameter_name_t g_video_parameter_name[] = {IMGSENSOR_ID_ISO_SENSITIVITY, "ISO sensitivity"}, {IMGSENSOR_ID_ISO_SENSITIVITY_AUTO, "Automatic ISO sensitivity"}, {IMGSENSOR_ID_EXPOSURE_METERING, "Photometry"}, + {IMGSENSOR_ID_SPOT_POSITION, "Spot position"}, {IMGSENSOR_ID_3A_LOCK, "Lock AWB/AE"}, {IMGSENSOR_ID_AUTO_FOCUS_START, "Start single Auto Focus"}, {IMGSENSOR_ID_AUTO_FOCUS_STOP, "Stop single Auto Focus"}, @@ -906,6 +908,7 @@ static void initialize_scene_parameter(video_scene_params_t *sp) sp->iso_auto = get_default_value(IMGSENSOR_ID_ISO_SENSITIVITY_AUTO); sp->iso = get_default_value(IMGSENSOR_ID_ISO_SENSITIVITY); sp->meter = get_default_value(IMGSENSOR_ID_EXPOSURE_METERING); + sp->spot_pos = get_default_value(IMGSENSOR_ID_SPOT_POSITION); sp->threea_lock = get_default_value(IMGSENSOR_ID_3A_LOCK); sp->led = get_default_value(IMGSENSOR_ID_FLASH_LED_MODE); sp->jpeg_quality = get_default_value(IMGSENSOR_ID_JPEG_QUALITY); @@ -2381,6 +2384,7 @@ static int reflect_scene_parameter(enum v4l2_scene_mode mode) } set_intvalue(IMGSENSOR_ID_EXPOSURE_METERING, sp->meter); + set_intvalue(IMGSENSOR_ID_SPOT_POSITION, sp->spot_pos); set_intvalue(IMGSENSOR_ID_3A_LOCK, sp->threea_lock); set_intvalue(IMGSENSOR_ID_FLASH_LED_MODE, sp->led); set_intvalue(IMGSENSOR_ID_JPEG_QUALITY, sp->jpeg_quality); @@ -2621,6 +2625,10 @@ static int read_scene_param(enum v4l2_scene_mode mode, control->value = sp->meter; break; + case IMGSENSOR_ID_SPOT_POSITION: + control->value = sp->spot_pos; + break; + case IMGSENSOR_ID_3A_LOCK: control->value = sp->threea_lock; break; @@ -2932,6 +2940,10 @@ static int save_scene_param(enum v4l2_scene_mode mode, sp->meter = control->value; break; + case IMGSENSOR_ID_SPOT_POSITION: + sp->spot_pos = control->value; + break; + case IMGSENSOR_ID_3A_LOCK: sp->threea_lock = control->value; break; diff --git a/include/nuttx/video/imgsensor.h b/include/nuttx/video/imgsensor.h index bde3f09ebd..444c411cd6 100644 --- a/include/nuttx/video/imgsensor.h +++ b/include/nuttx/video/imgsensor.h @@ -69,6 +69,7 @@ #define IMGSENSOR_ID_ISO_SENSITIVITY (0x0001000d) #define IMGSENSOR_ID_ISO_SENSITIVITY_AUTO (0x0001000e) #define IMGSENSOR_ID_EXPOSURE_METERING (0x0001000f) +#define IMGSENSOR_ID_SPOT_POSITION (0x00010016) #define IMGSENSOR_ID_3A_LOCK (0x00010011) #define IMGSENSOR_ID_AUTO_FOCUS_START (0x00010012) #define IMGSENSOR_ID_AUTO_FOCUS_STOP (0x00010013) diff --git a/include/nuttx/video/video_controls.h b/include/nuttx/video/video_controls.h index fc9478d50c..b6ce4ef119 100644 --- a/include/nuttx/video/video_controls.h +++ b/include/nuttx/video/video_controls.h @@ -202,6 +202,10 @@ enum v4l2_scene_mode #define V4L2_3A_STATUS_AWB_OPERATING (1 << 1) /**< AWB is operating */ #define V4L2_3A_STATUS_AF_OPERATING (1 << 2) /**< AF is operating */ +/** Spot position in spot exposure metering */ + +#define V4L2_CID_EXPOSURE_METERING_SPOT_POSITION (22) + /** Flash and privacy (indicator) light controls */ #define V4L2_CID_FLASH_LED_MODE (0)