/* 
 | 
 *  Copyright (c) 2019 Rockchip Corporation 
 | 
 * 
 | 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 | 
 * you may not use this file except in compliance with the License. 
 | 
 * You may obtain a copy of the License at 
 | 
 * 
 | 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 | 
 * 
 | 
 * Unless required by applicable law or agreed to in writing, software 
 | 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 | 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 | 
 * See the License for the specific language governing permissions and 
 | 
 * limitations under the License. 
 | 
 * 
 | 
 */ 
 | 
  
 | 
#include "FlashLight.h" 
 | 
#include "xcam_log.h" 
 | 
#include "linux/rk-led-flash.h" 
 | 
  
 | 
namespace RkCam { 
 | 
  
 | 
FlashLightHw::FlashLightHw(std::string name[], int num) 
 | 
{ 
 | 
    if (num >= FLASH_MAX_NUM) { 
 | 
        LOGE_CAMHW_SUBM(FL_SUBM, "not support flash num %d", num); 
 | 
        return ; 
 | 
    } 
 | 
  
 | 
    _dev_num = 0; 
 | 
    for (int i = 0 ; i < num; i++) { 
 | 
        _fl_device[i] = new V4l2SubDevice(name[i].c_str()); 
 | 
        _dev_num++; 
 | 
    } 
 | 
    _active_fl_num = 0; 
 | 
    _keep_status = false; 
 | 
    xcam_mem_clear (_flash_settings); 
 | 
} 
 | 
  
 | 
FlashLightHw::~FlashLightHw() 
 | 
{ 
 | 
  
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::init(int active_num) 
 | 
{ 
 | 
    XCAM_ASSERT (active_num <= _dev_num); 
 | 
  
 | 
    for (int i = 0 ; i < active_num; i++) { 
 | 
        _fl_device[i]->open(); 
 | 
        _active_fl_num++; 
 | 
    } 
 | 
  
 | 
    get_flash_info (); 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::deinit() 
 | 
{ 
 | 
    if (!_keep_status) { 
 | 
        v4l_set_params(RK_AIQ_FLASH_MODE_OFF, 0, 0, false); 
 | 
        xcam_mem_clear (_flash_settings); 
 | 
    } 
 | 
    for (int i = 0 ; i < _active_fl_num; i++) { 
 | 
        _fl_device[i]->close(); 
 | 
    } 
 | 
    _active_fl_num = 0; 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::start() 
 | 
{ 
 | 
    for (int i = 0 ; i < _active_fl_num; i++) { 
 | 
        _fl_device[i]->start(); 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::stop() 
 | 
{ 
 | 
    if (!_keep_status) { 
 | 
        v4l_set_params(RK_AIQ_FLASH_MODE_OFF, 0, 0, false); 
 | 
        xcam_mem_clear (_flash_settings); 
 | 
    } 
 | 
    for (int i = 0 ; i < _active_fl_num; i++) { 
 | 
        _fl_device[i]->stop(); 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::set_params(rk_aiq_flash_setting_t& flash_settings) 
 | 
{ 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
    // set flash if needed 
 | 
    rk_aiq_flash_setting_t* old_flash_settings = &_flash_settings; 
 | 
    if ((old_flash_settings->flash_mode != flash_settings.flash_mode) || 
 | 
            (old_flash_settings->strobe != flash_settings.strobe) || 
 | 
            (old_flash_settings->power[0] != flash_settings.power[0]) || 
 | 
            (old_flash_settings->power[1] != flash_settings.power[1]) 
 | 
       ) { 
 | 
       LOGD_CAMHW_SUBM(FL_SUBM, "flash_settings: mode:%d,power:%f,timeout_ms:%d,strobe:%d", 
 | 
                             flash_settings.flash_mode, flash_settings.power[0], 
 | 
                             flash_settings.timeout_ms, flash_settings.strobe); 
 | 
        ret = v4l_set_params(flash_settings.flash_mode, flash_settings.power, 
 | 
                             flash_settings.timeout_ms, flash_settings.strobe); 
 | 
        if (!ret) 
 | 
            _flash_settings = flash_settings; 
 | 
    } 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::get_status (rk_aiq_flash_setting_t& flash_settings, int frame_id) 
 | 
{ 
 | 
    if (!_active_fl_num) 
 | 
        return XCAM_RETURN_ERROR_FAILED; 
 | 
  
 | 
    flash_settings = _flash_settings; 
 | 
  
 | 
    if (_fl_device[0].ptr()) { 
 | 
        struct timeval flash_time; 
 | 
  
 | 
        if (_fl_device[0]->io_control (RK_VIDIOC_FLASH_TIMEINFO, &flash_time) < 0) { 
 | 
            LOGE_CAMHW_SUBM(FL_SUBM, " get RK_VIDIOC_FLASH_TIMEINFO failed. cmd = 0x%x", RK_VIDIOC_FLASH_TIMEINFO); 
 | 
            /* return XCAM_RETURN_ERROR_IOCTL; */ 
 | 
        } 
 | 
        flash_settings.effect_ts = (int64_t)flash_time.tv_sec * 1000 * 1000 + 
 | 
                                   (int64_t)flash_time.tv_usec; 
 | 
        LOGD_CAMHW_SUBM(FL_SUBM, "frameid %d, get RK_VIDIOC_FLASH_TIMEINFO flash ts %lld", 
 | 
                        frame_id, flash_settings.effect_ts); 
 | 
    } 
 | 
  
 | 
    // for the following case: 
 | 
    // 1) set to flash mode 
 | 
    // 2) one flash power set to 0 
 | 
    // then we can't get the effect ts from the node which power set to 0 
 | 
    if (_fl_device[1].ptr() && flash_settings.effect_ts == 0 && 
 | 
            flash_settings.power[0] != flash_settings.power[1]) { 
 | 
        struct timeval flash_time; 
 | 
  
 | 
        if (_fl_device[1]->io_control (RK_VIDIOC_FLASH_TIMEINFO, &flash_time) < 0) { 
 | 
            LOGE_CAMHW_SUBM(FL_SUBM, " get RK_VIDIOC_FLASH_TIMEINFO failed. cmd = 0x%x", RK_VIDIOC_FLASH_TIMEINFO); 
 | 
            /* return XCAM_RETURN_ERROR_IOCTL; */ 
 | 
        } 
 | 
        flash_settings.effect_ts = (int64_t)flash_time.tv_sec * 1000 * 1000 + 
 | 
                                   (int64_t)flash_time.tv_usec; 
 | 
        LOGD_CAMHW_SUBM(FL_SUBM, "frameid %d, get RK_VIDIOC_FLASH_TIMEINFO flash ts %lld", 
 | 
                        frame_id, flash_settings.effect_ts); 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
FlashLightHw::v4l_set_params(int fl_mode, float fl_intensity[], int fl_timeout, int fl_on) 
 | 
{ 
 | 
    struct v4l2_control control; 
 | 
    int fl_v4l_mode; 
 | 
    int i = 0; 
 | 
#define set_fl_contol_to_dev(fl_dev,control_id,val) \ 
 | 
        {\ 
 | 
            xcam_mem_clear (control); \ 
 | 
            control.id = control_id; \ 
 | 
            control.value = val; \ 
 | 
            if (fl_dev->io_control (VIDIOC_S_CTRL, &control) < 0) { \ 
 | 
                LOGE_CAMHW_SUBM(FL_SUBM, " set fl %s to %d failed", #control_id, val); \ 
 | 
                return XCAM_RETURN_ERROR_IOCTL; \ 
 | 
            } \ 
 | 
            LOGD_CAMHW_SUBM(FL_SUBM, "set fl %p, cid %s to %d, success",\ 
 | 
                            fl_dev.ptr(), #control_id, val); \ 
 | 
        }\ 
 | 
  
 | 
    if (fl_mode == RK_AIQ_FLASH_MODE_OFF) 
 | 
        fl_v4l_mode = V4L2_FLASH_LED_MODE_NONE; 
 | 
    else if (fl_mode == RK_AIQ_FLASH_MODE_FLASH || fl_mode == RK_AIQ_FLASH_MODE_FLASH_MAIN) 
 | 
        fl_v4l_mode = V4L2_FLASH_LED_MODE_FLASH; 
 | 
    else if (fl_mode == RK_AIQ_FLASH_MODE_FLASH_PRE || fl_mode ==  RK_AIQ_FLASH_MODE_TORCH) 
 | 
        fl_v4l_mode = V4L2_FLASH_LED_MODE_TORCH; 
 | 
    else { 
 | 
        LOGE_CAMHW_SUBM(FL_SUBM, " set fl to mode  %d failed", fl_mode); 
 | 
        return XCAM_RETURN_ERROR_PARAM; 
 | 
    } 
 | 
  
 | 
    SmartPtr<V4l2SubDevice> fl_device; 
 | 
  
 | 
    if (fl_v4l_mode == V4L2_FLASH_LED_MODE_NONE) { 
 | 
        for (i = 0; i < _active_fl_num; i++) { 
 | 
            fl_device = _fl_device[i]; 
 | 
            set_fl_contol_to_dev(fl_device, V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_NONE); 
 | 
        } 
 | 
    } else if (fl_v4l_mode == V4L2_FLASH_LED_MODE_FLASH) { 
 | 
        for (i = 0; i < _active_fl_num; i++) { 
 | 
            fl_device = _fl_device[i]; 
 | 
            set_fl_contol_to_dev(fl_device, V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_FLASH); 
 | 
            set_fl_contol_to_dev(fl_device, V4L2_CID_FLASH_TIMEOUT, fl_timeout * 1000); 
 | 
            if (_v4l_flash_info[i].fl_strth_adj_enable) { 
 | 
                int flash_power = 
 | 
                    fl_intensity[i] * (_v4l_flash_info[i].flash_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MAX]); 
 | 
                set_fl_contol_to_dev(fl_device, V4L2_CID_FLASH_INTENSITY, flash_power); 
 | 
                LOGD_CAMHW_SUBM(FL_SUBM, "set flash: flash:%f max:%d set:%d\n", 
 | 
                                fl_intensity[i], 
 | 
                                _v4l_flash_info[i].flash_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MAX], 
 | 
                                flash_power); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        // shoude flash on all finally 
 | 
        for (i = 0; i < _active_fl_num; i++) { 
 | 
            set_fl_contol_to_dev(fl_device, 
 | 
                                 fl_on ? V4L2_CID_FLASH_STROBE : V4L2_CID_FLASH_STROBE_STOP, 0); 
 | 
        } 
 | 
    } else if (fl_v4l_mode == V4L2_FLASH_LED_MODE_TORCH) { 
 | 
        for (i = 0; i < _active_fl_num; i++) { 
 | 
            fl_device = _fl_device[i]; 
 | 
            if (_v4l_flash_info[i].tc_strth_adj_enable) { 
 | 
                int torch_power = 
 | 
                    fl_intensity[i] * (_v4l_flash_info[i].torch_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MAX]); 
 | 
                set_fl_contol_to_dev(fl_device, V4L2_CID_FLASH_TORCH_INTENSITY, torch_power); 
 | 
                LOGD_CAMHW_SUBM(FL_SUBM, "set flash: torch:%f max:%d set:%d\n", 
 | 
                                fl_intensity[i], 
 | 
                                _v4l_flash_info[i].torch_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MAX], 
 | 
                                torch_power); 
 | 
            } 
 | 
            set_fl_contol_to_dev(fl_device, V4L2_CID_FLASH_LED_MODE, V4L2_FLASH_LED_MODE_TORCH); 
 | 
        } 
 | 
    } else { 
 | 
        LOGE_CAMHW_SUBM(FL_SUBM, "|||set_3a_fl error fl mode %d", fl_mode); 
 | 
        return XCAM_RETURN_ERROR_PARAM; 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
int 
 | 
FlashLightHw::get_flash_info () 
 | 
{ 
 | 
    struct v4l2_queryctrl ctrl; 
 | 
    int flash_power, torch_power; 
 | 
    SmartPtr<V4l2SubDevice> fl_device; 
 | 
  
 | 
    for (int i = 0; i < _active_fl_num; i++) { 
 | 
        fl_device = _fl_device[i]; 
 | 
  
 | 
        memset(&ctrl, 0, sizeof(ctrl)); 
 | 
        ctrl.id = V4L2_CID_FLASH_INTENSITY; 
 | 
        if (fl_device->io_control(VIDIOC_QUERYCTRL, &ctrl) < 0) { 
 | 
            LOGE_CAMHW_SUBM(FL_SUBM, "query V4L2_CID_FLASH_INTENSITY failed. cmd = 0x%x", 
 | 
                            V4L2_CID_FLASH_INTENSITY); 
 | 
            return -errno; 
 | 
        } 
 | 
  
 | 
        _v4l_flash_info[i].flash_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MIN] = 
 | 
            ctrl.minimum; 
 | 
        _v4l_flash_info[i].flash_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MAX] = 
 | 
            ctrl.maximum; 
 | 
        _v4l_flash_info[i].flash_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_DEFAULT] = 
 | 
            ctrl.default_value; 
 | 
        _v4l_flash_info[i].flash_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_STEP] = 
 | 
            ctrl.step; 
 | 
        _v4l_flash_info[i].fl_strth_adj_enable = !(ctrl.flags & V4L2_CTRL_FLAG_READ_ONLY); 
 | 
  
 | 
        LOGD_CAMHW_SUBM(FL_SUBM, "fl_dev[%d], flash power range:[%d,%d], adjust enable %d", 
 | 
                        i, ctrl.minimum, ctrl.maximum, _v4l_flash_info[i].fl_strth_adj_enable); 
 | 
  
 | 
        memset(&ctrl, 0, sizeof(ctrl)); 
 | 
        ctrl.id = V4L2_CID_FLASH_TORCH_INTENSITY; 
 | 
        if (fl_device->io_control(VIDIOC_QUERYCTRL, &ctrl) < 0) { 
 | 
            LOGE_CAMHW_SUBM(FL_SUBM, "query V4L2_CID_FLASH_TORCH_INTENSITY failed. cmd = 0x%x", 
 | 
                            V4L2_CID_FLASH_TORCH_INTENSITY); 
 | 
            return -errno; 
 | 
        } 
 | 
  
 | 
        _v4l_flash_info[i].torch_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MIN] = 
 | 
            ctrl.minimum; 
 | 
        _v4l_flash_info[i].torch_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_MAX] = 
 | 
            ctrl.maximum; 
 | 
        _v4l_flash_info[i].torch_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_DEFAULT] = 
 | 
            ctrl.default_value; 
 | 
        _v4l_flash_info[i].torch_power_info[RK_AIQ_V4L_FLASH_QUERY_TYPE_E_STEP] = 
 | 
            ctrl.step; 
 | 
  
 | 
        _v4l_flash_info[i].tc_strth_adj_enable = !(ctrl.flags & V4L2_CTRL_FLAG_READ_ONLY); 
 | 
  
 | 
  
 | 
        LOGD_CAMHW_SUBM(FL_SUBM, "fl_dev[%d], torch power range:[%d,%d], adjust enable %d", 
 | 
                        i, ctrl.minimum, ctrl.maximum, _v4l_flash_info[i].tc_strth_adj_enable); 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
}; 
 |