/* 
 | 
 *  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 <sys/stat.h> 
 | 
#include "Isp20PollThread.h" 
 | 
#include "Isp20StatsBuffer.h" 
 | 
#include "rkisp2-config.h" 
 | 
#include "SensorHw.h" 
 | 
#include "LensHw.h" 
 | 
#include "Isp20_module_dbg.h" 
 | 
#include <fcntl.h> 
 | 
  
 | 
#ifndef DIV_ROUND_UP 
 | 
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 
 | 
#endif 
 | 
  
 | 
#ifdef ANDROID_OS 
 | 
#define DEFAULT_CAPTURE_RAW_PATH "/data/capture_image" 
 | 
#define CAPTURE_CNT_FILENAME "/data/.capture_cnt" 
 | 
#else 
 | 
#define DEFAULT_CAPTURE_RAW_PATH "/tmp/capture_image" 
 | 
#define CAPTURE_CNT_FILENAME "/tmp/.capture_cnt" 
 | 
#endif 
 | 
  
 | 
#define WRITE_RAW_FILE_HEADER 
 | 
/* 
 | 
 * #define WRITE_ISP_REG 
 | 
 * #define WRITE_ISPP_REG 
 | 
 */ 
 | 
#define ISP_REGS_BASE 0xffb50000 
 | 
#define ISPP_REGS_BASE 0xffb60000 
 | 
  
 | 
#define RAW_FILE_IDENT 0x8080 
 | 
#define HEADER_LEN 128U 
 | 
  
 | 
/* 
 | 
 * Raw file structure: 
 | 
 * 
 | 
+------------+-----------------+-------------+-----------------+---------------------------+ 
 | 
|    ITEM    |    PARAMETER    |  DATA TYPE  |  LENGTH(Bytes)  |        DESCRIPTION        | 
 | 
+------------+-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |     Identifier  |  uint16_t   |       2         |  fixed 0x8080             | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |  Header length  |  uint16_t   |       2         |  fixed 128U               | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |    Frame index  |  uint32_t   |       4         |                           | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |          Width  |  uint16_t   |       2         |  image width              | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |         Height  |  uint16_t   |       2         |  image height             | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |      Bit depth  |   uint8_t   |       1         |  image bit depth          | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |                 |             |                 |  0: BGGR;  1: GBRG;       | 
 | 
|            |   Bayer format  |   uint8_t   |       1         |  2: GRBG;  3: RGGB;       | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |                 |             |                 |  1: linear                | 
 | 
|    FRAME   |  Number of HDR  |             |                 |  2: long + short          | 
 | 
|   HEADER   |      frame      |   uint8_t   |       1         |  3: long + mid + short    | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |                 |             |                 |  1: short                 | 
 | 
|            |  Current frame  |             |                 |  2: mid                   | 
 | 
|            |       type      |   uint8_t   |       1         |  3: long                  | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |   Storage type  |   uint8_t   |       1         |  0: packed; 1: unpacked   | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |    Line stride  |  uint16_t   |       2         |  In bytes                 | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |     Effective   |             |                 |                           | 
 | 
|            |    line stride  |  uint16_t   |       2         |  In bytes                 | 
 | 
|            +-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |       Reserved  |   uint8_t   |      107        |                           | 
 | 
+------------+-----------------+-------------+-----------------+---------------------------+ 
 | 
|            |                 |             |                 |                           | 
 | 
|  RAW DATA  |       RAW DATA  |    RAW      |  W * H * bpp    |  RAW DATA                 | 
 | 
|            |                 |             |                 |                           | 
 | 
+------------+-----------------+-------------+-----------------+---------------------------+ 
 | 
  
 | 
 */ 
 | 
  
 | 
/* 
 | 
 * the structure of measuure parameters from isp in meta_data file: 
 | 
 * 
 | 
 * "frame%08d-l_m_s-gain[%08.5f_%08.5f_%08.5f]-time[%08.5f_%08.5f_%08.5f]-awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]" 
 | 
 * 
 | 
 */ 
 | 
  
 | 
namespace RkCam { 
 | 
  
 | 
const struct capture_fmt Isp20PollThread::csirx_fmts[] = 
 | 
{ 
 | 
    /* raw */ 
 | 
    { 
 | 
        .fourcc = V4L2_PIX_FMT_SRGGB8, 
 | 
        .bayer_fmt = 3, 
 | 
        .pcpp = 1, 
 | 
        .bpp = { 8 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SGRBG8, 
 | 
        .bayer_fmt = 2, 
 | 
        .pcpp = 1, 
 | 
        .bpp = { 8 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SGBRG8, 
 | 
        .bayer_fmt = 1, 
 | 
        .pcpp = 1, 
 | 
        .bpp = { 8 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SBGGR8, 
 | 
        .bayer_fmt = 0, 
 | 
        .pcpp = 1, 
 | 
        .bpp = { 8 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SRGGB10, 
 | 
        .bayer_fmt = 3, 
 | 
        .pcpp = 4, 
 | 
        .bpp = { 10 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SGRBG10, 
 | 
        .bayer_fmt = 2, 
 | 
        .pcpp = 4, 
 | 
        .bpp = { 10 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SGBRG10, 
 | 
        .bayer_fmt = 1, 
 | 
        .pcpp = 4, 
 | 
        .bpp = { 10 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SBGGR10, 
 | 
        .bayer_fmt = 0, 
 | 
        .pcpp = 4, 
 | 
        .bpp = { 10 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SRGGB12, 
 | 
        .bayer_fmt = 3, 
 | 
        .pcpp = 2, 
 | 
        .bpp = { 12 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SGRBG12, 
 | 
        .bayer_fmt = 2, 
 | 
        .pcpp = 2, 
 | 
        .bpp = { 12 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SGBRG12, 
 | 
        .bayer_fmt = 1, 
 | 
        .pcpp = 2, 
 | 
        .bpp = { 12 }, 
 | 
    }, { 
 | 
        .fourcc = V4L2_PIX_FMT_SBGGR12, 
 | 
        .bayer_fmt = 0, 
 | 
        .pcpp = 2, 
 | 
        .bpp = { 12 }, 
 | 
    }, 
 | 
}; 
 | 
  
 | 
const char* 
 | 
Isp20PollThread::mipi_poll_type_to_str[ISP_POLL_MIPI_MAX] = 
 | 
{ 
 | 
    "mipi_tx_poll", 
 | 
    "mipi_rx_poll", 
 | 
}; 
 | 
  
 | 
class MipiPollThread 
 | 
    : public Thread 
 | 
{ 
 | 
public: 
 | 
    MipiPollThread (Isp20PollThread*poll, int type, int dev_index) 
 | 
        : Thread (Isp20PollThread::mipi_poll_type_to_str[type]) 
 | 
        , _poll (poll) 
 | 
        , _type (type) 
 | 
        , _dev_index (dev_index) 
 | 
    {} 
 | 
  
 | 
protected: 
 | 
    virtual bool loop () { 
 | 
        XCamReturn ret = _poll->mipi_poll_buffer_loop (_type, _dev_index); 
 | 
  
 | 
        if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT || 
 | 
                XCAM_RETURN_BYPASS) 
 | 
            return true; 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
private: 
 | 
    Isp20PollThread *_poll; 
 | 
    int _type; 
 | 
    int _dev_index; 
 | 
}; 
 | 
  
 | 
bool 
 | 
Isp20PollThread::get_value_from_file(const char* path, int& value, uint32_t& frameId) 
 | 
{ 
 | 
    const char *delim = " "; 
 | 
    char buffer[16] = {0}; 
 | 
    int fp; 
 | 
  
 | 
    fp = open(path, O_RDONLY | O_SYNC); 
 | 
    if (fp != -1) { 
 | 
        if (read(fp, buffer, sizeof(buffer)) <= 0) { 
 | 
            LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "%s read %s failed!\n", __func__, path); 
 | 
        } else { 
 | 
            char *p = nullptr; 
 | 
  
 | 
            p = strtok(buffer, delim); 
 | 
            if (p != nullptr) { 
 | 
                value = atoi(p); 
 | 
                p = strtok(nullptr, delim); 
 | 
                if (p != nullptr) 
 | 
                    frameId = atoi(p); 
 | 
            } 
 | 
        } 
 | 
        close(fp); 
 | 
        LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "value: %d, frameId: %d\n", value, frameId); 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    return false; 
 | 
} 
 | 
  
 | 
  
 | 
bool 
 | 
Isp20PollThread::set_value_to_file(const char* path, int value, uint32_t sequence) 
 | 
{ 
 | 
    char buffer[16] = {0}; 
 | 
    int fp; 
 | 
  
 | 
    fp = open(path, O_CREAT | O_RDWR | O_SYNC, S_IRWXU | S_IRUSR | S_IXUSR | S_IROTH | S_IXOTH); 
 | 
    if (fp != -1) { 
 | 
        ftruncate(fp, 0); 
 | 
        lseek(fp, 0, SEEK_SET); 
 | 
        snprintf(buffer, sizeof(buffer), "%3d %8d\n", _capture_raw_num, sequence); 
 | 
        if (write(fp, buffer, sizeof(buffer)) <= 0) 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s write %s failed!\n", __func__, path); 
 | 
        close(fp); 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    return false; 
 | 
} 
 | 
  
 | 
SmartPtr<VideoBuffer> 
 | 
Isp20PollThread::new_video_buffer(SmartPtr<V4l2Buffer> buf, 
 | 
                                  SmartPtr<V4l2Device> dev, 
 | 
                                  int type) 
 | 
{ 
 | 
    ENTER_CAMHW_FUNCTION(); 
 | 
    SmartPtr<VideoBuffer> video_buf = nullptr; 
 | 
  
 | 
    if (type == ISP_POLL_3A_STATS) { 
 | 
        rkisp_effect_params_v20 ispParams = {0}; 
 | 
        SmartPtr<RkAiqExpParamsProxy> expParams = nullptr; 
 | 
        SmartPtr<RkAiqIrisParamsProxy> irisParams = nullptr; 
 | 
        SmartPtr<RkAiqAfInfoProxy> afParams = nullptr; 
 | 
  
 | 
        //get exp params 
 | 
        _event_handle_dev->getEffectiveExpParams(expParams, buf->get_buf().sequence); 
 | 
  
 | 
        if (_focus_handle_dev.ptr()) { 
 | 
            _focus_handle_dev->getAfInfoParams(afParams, buf->get_buf().sequence); 
 | 
            _focus_handle_dev->getIrisInfoParams(irisParams, buf->get_buf().sequence); 
 | 
  
 | 
        } 
 | 
  
 | 
        if (mCamHw) { 
 | 
            if (mCamHw->getEffectiveIspParams(ispParams, buf->get_buf().sequence) != XCAM_RETURN_NO_ERROR) 
 | 
                LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "sequence(%d), get ispparams failed!!!\n", 
 | 
                        buf->get_buf().sequence); 
 | 
        } 
 | 
  
 | 
        video_buf = new Isp20StatsBuffer(buf, dev, _event_handle_dev, mCamHw, afParams, irisParams); 
 | 
  
 | 
        // write metadata && isp/ispp reg for debug 
 | 
        if (_capture_metadata_num > 0) { 
 | 
            char file_name[32] = {0}; 
 | 
            int capture_cnt = 0; 
 | 
            uint32_t rawFrmId = 0; 
 | 
  
 | 
            snprintf(file_name, sizeof(file_name), "%s", CAPTURE_CNT_FILENAME); 
 | 
            get_value_from_file(file_name, capture_cnt, rawFrmId); 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "rawFrmId: %d, sequence: %d, _capture_metadata_num: %d\n", 
 | 
                            rawFrmId, buf->get_buf().sequence, 
 | 
                            _capture_metadata_num); 
 | 
            if (_is_raw_dir_exist && buf->get_buf().sequence >= rawFrmId && \ 
 | 
                expParams.ptr()) 
 | 
#ifdef WRITE_ISP_REG 
 | 
                write_reg_to_file(ISP_REGS_BASE, 0x0, 0x6000, buf->get_buf().sequence); 
 | 
#endif 
 | 
#ifdef WRITE_ISPP_REG 
 | 
            write_reg_to_file(ISPP_REGS_BASE, 0x0, 0xc94, buf->get_buf().sequence); 
 | 
#endif 
 | 
            write_metadata_to_file(raw_dir_path, 
 | 
                                   buf->get_buf().sequence, 
 | 
                                   ispMeasParams, expParams, afParams); 
 | 
            _capture_metadata_num--; 
 | 
            if (!_capture_metadata_num) { 
 | 
                _is_raw_dir_exist = false; 
 | 
                if (_capture_raw_type == CAPTURE_RAW_SYNC) { 
 | 
                    _capture_image_mutex.lock(); 
 | 
                    _capture_image_cond.broadcast(); 
 | 
                    _capture_image_mutex.unlock(); 
 | 
                } 
 | 
  
 | 
                LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "stop capturing raw!\n"); 
 | 
            } 
 | 
        } 
 | 
    } else 
 | 
        return PollThread::new_video_buffer(buf, dev, type); 
 | 
    EXIT_CAMHW_FUNCTION(); 
 | 
  
 | 
    return video_buf; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::notify_sof (uint64_t time, int frameid) 
 | 
{ 
 | 
    ENTER_CAMHW_FUNCTION(); 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
  
 | 
    XCAM_ASSERT(_event_handle_dev.ptr()); 
 | 
    ret = _event_handle_dev->handle_sof(time, frameid); 
 | 
    if (get_rkaiq_runtime_dbg() > 0) { 
 | 
        XCAM_STATIC_FPS_CALCULATION(SOF_FPS, 60); 
 | 
    } 
 | 
    if (_focus_handle_dev.ptr()) 
 | 
        _focus_handle_dev->handle_sof(time, frameid); 
 | 
  
 | 
    _sof_map_mutex.lock(); 
 | 
    while (_sof_timestamp_map.size() > 8) 
 | 
        _sof_timestamp_map.erase(_sof_timestamp_map.begin()); 
 | 
    _sof_timestamp_map[frameid] = time; 
 | 
    _sof_map_mutex.unlock(); 
 | 
    EXIT_CAMHW_FUNCTION(); 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
bool 
 | 
Isp20PollThread::set_event_handle_dev(SmartPtr<BaseSensorHw> &dev) 
 | 
{ 
 | 
    ENTER_CAMHW_FUNCTION(); 
 | 
    XCAM_ASSERT (dev.ptr()); 
 | 
    _event_handle_dev = dev; 
 | 
  
 | 
    rk_aiq_exposure_sensor_descriptor sns_des; 
 | 
    dev->get_format(&sns_des); 
 | 
    sns_width = sns_des.sensor_output_width; 
 | 
    sns_height = sns_des.sensor_output_height; 
 | 
    pixelformat = sns_des.sensor_pixelformat; 
 | 
  
 | 
  
 | 
    if (!_linked_to_isp) { 
 | 
        XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
  
 | 
        // get sensor crop bounds 
 | 
        struct v4l2_subdev_selection sns_sd_sel; 
 | 
        memset(&sns_sd_sel, 0, sizeof(sns_sd_sel)); 
 | 
  
 | 
        ret = dev->get_selection(0, V4L2_SEL_TGT_CROP_BOUNDS, sns_sd_sel); 
 | 
        if (ret) { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "get_selection failed !\n"); 
 | 
        } else { 
 | 
            if (sns_width != sns_sd_sel.r.width || 
 | 
                    sns_height != sns_sd_sel.r.height) { 
 | 
                sns_width = sns_sd_sel.r.width; 
 | 
                sns_height = sns_sd_sel.r.height; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    EXIT_CAMHW_FUNCTION(); 
 | 
    return true; 
 | 
} 
 | 
  
 | 
bool 
 | 
Isp20PollThread::set_focus_handle_dev(SmartPtr<LensHw> &dev) 
 | 
{ 
 | 
    ENTER_CAMHW_FUNCTION(); 
 | 
    XCAM_ASSERT (dev.ptr()); 
 | 
    _focus_handle_dev = dev; 
 | 
    EXIT_CAMHW_FUNCTION(); 
 | 
    return true; 
 | 
} 
 | 
  
 | 
bool 
 | 
Isp20PollThread::setCamHw(ICamHw *dev) 
 | 
{ 
 | 
    ENTER_CAMHW_FUNCTION(); 
 | 
    XCAM_ASSERT (dev); 
 | 
    mCamHw = dev; 
 | 
    EXIT_CAMHW_FUNCTION(); 
 | 
    return true; 
 | 
} 
 | 
  
 | 
Isp20PollThread::Isp20PollThread() 
 | 
    : PollThread() 
 | 
    , _first_trigger(true) 
 | 
    , sns_width(0) 
 | 
    , sns_height(0) 
 | 
    , _is_raw_dir_exist(false) 
 | 
    , _is_capture_raw(false) 
 | 
    , _capture_raw_num(0) 
 | 
    , _capture_metadata_num(0) 
 | 
    , _capture_image_mutex(false) 
 | 
    , _capture_image_cond(false) 
 | 
    ,  _capture_raw_type(CAPTURE_RAW_ASYNC) 
 | 
    , _is_multi_cam_conc(false) 
 | 
    , _skip_num(0) 
 | 
    , _skip_to_seq(0) 
 | 
    , _need_luma_rd_info(true) 
 | 
{ 
 | 
    for (int i = 0; i < 3; i++) { 
 | 
        SmartPtr<MipiPollThread> mipi_poll = new MipiPollThread(this, ISP_POLL_MIPI_TX, i); 
 | 
        XCAM_ASSERT (mipi_poll.ptr ()); 
 | 
        _isp_mipi_tx_infos[i].loop = mipi_poll; 
 | 
  
 | 
        mipi_poll = new MipiPollThread(this, ISP_POLL_MIPI_RX, i); 
 | 
        XCAM_ASSERT (mipi_poll.ptr ()); 
 | 
        _isp_mipi_rx_infos[i].loop = mipi_poll; 
 | 
  
 | 
        _isp_mipi_tx_infos[i].stop_fds[0] = -1; 
 | 
        _isp_mipi_tx_infos[i].stop_fds[1] = -1; 
 | 
        _isp_mipi_rx_infos[i].stop_fds[0] = -1; 
 | 
        _isp_mipi_rx_infos[i].stop_fds[1] = -1; 
 | 
  
 | 
    } 
 | 
  
 | 
    LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "Isp20PollThread constructed"); 
 | 
} 
 | 
  
 | 
Isp20PollThread::~Isp20PollThread() 
 | 
{ 
 | 
    stop(); 
 | 
  
 | 
    LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "~Isp20PollThread destructed"); 
 | 
} 
 | 
  
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::start () 
 | 
{ 
 | 
    if (create_stop_fds_mipi()) { 
 | 
        LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "create mipi stop fds failed !"); 
 | 
        return XCAM_RETURN_ERROR_UNKNOWN; 
 | 
    } 
 | 
  
 | 
    for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
        _isp_mipi_tx_infos[i].loop->start (); 
 | 
        _isp_mipi_rx_infos[i].loop->start (); 
 | 
    } 
 | 
    return PollThread::start (); 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::stop () 
 | 
{ 
 | 
    for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
        if (_isp_mipi_tx_infos[i].dev.ptr ()) { 
 | 
            if (_isp_mipi_tx_infos[i].stop_fds[1] != -1) { 
 | 
                char buf = 0xf;  // random value to write to flush fd. 
 | 
                unsigned int size = write(_isp_mipi_tx_infos[i].stop_fds[1], &buf, sizeof(char)); 
 | 
                if (size != sizeof(char)) 
 | 
                    LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "Flush write not completed"); 
 | 
            } 
 | 
            _isp_mipi_tx_infos[i].loop->stop (); 
 | 
            /* _isp_mipi_tx_infos[i].buf_list.clear (); */ 
 | 
            /* _isp_mipi_tx_infos[i].cache_list.clear (); */ 
 | 
        } 
 | 
  
 | 
        if (_isp_mipi_rx_infos[i].dev.ptr ()) { 
 | 
            if (_isp_mipi_rx_infos[i].stop_fds[1] != -1) { 
 | 
                char buf = 0xf;  // random value to write to flush fd. 
 | 
                unsigned int size = write(_isp_mipi_rx_infos[i].stop_fds[1], &buf, sizeof(char)); 
 | 
                if (size != sizeof(char)) 
 | 
                    LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "Flush write not completed"); 
 | 
            } 
 | 
            _isp_mipi_rx_infos[i].loop->stop (); 
 | 
            /* _isp_mipi_rx_infos[i].buf_list.clear (); */ 
 | 
            /* _isp_mipi_rx_infos[i].cache_list.clear (); */ 
 | 
        } 
 | 
    } 
 | 
  
 | 
    for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
        if (_isp_mipi_tx_infos[i].dev.ptr ()) { 
 | 
            _isp_mipi_tx_infos[i].buf_list.clear (); 
 | 
            _isp_mipi_tx_infos[i].cache_list.clear (); 
 | 
        } 
 | 
        if (_isp_mipi_rx_infos[i].dev.ptr ()) { 
 | 
            _isp_mipi_rx_infos[i].buf_list.clear (); 
 | 
            _isp_mipi_rx_infos[i].cache_list.clear (); 
 | 
        } 
 | 
    } 
 | 
    _mipi_trigger_mutex.lock(); 
 | 
    _isp_hdr_fid2times_map.clear(); 
 | 
    _isp_hdr_fid2ready_map.clear(); 
 | 
    _hdr_global_tmo_state_map.clear(); 
 | 
    _mipi_trigger_mutex.unlock(); 
 | 
    _sof_map_mutex.lock(); 
 | 
    _sof_timestamp_map.clear(); 
 | 
    _sof_map_mutex.unlock(); 
 | 
    destroy_stop_fds_mipi (); 
 | 
    _skip_num = 0; 
 | 
  
 | 
    return PollThread::stop (); 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::set_working_mode(int mode, bool linked_to_isp, bool nordbk) 
 | 
{ 
 | 
    _working_mode = mode; 
 | 
    _linked_to_isp = linked_to_isp; 
 | 
  
 | 
    switch (_working_mode) { 
 | 
    case RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR: 
 | 
    case RK_AIQ_ISP_HDR_MODE_3_LINE_HDR: 
 | 
        _mipi_dev_max = 3; 
 | 
        break; 
 | 
    case RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR: 
 | 
    case RK_AIQ_ISP_HDR_MODE_2_LINE_HDR: 
 | 
        _mipi_dev_max = 2; 
 | 
        break; 
 | 
    default: 
 | 
        _mipi_dev_max = 1; 
 | 
    } 
 | 
    if (nordbk) 
 | 
        _mipi_dev_max = 0; 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::set_mipi_devs(SmartPtr<V4l2Device> mipi_tx_devs[3], 
 | 
                               SmartPtr<V4l2Device> mipi_rx_devs[3], 
 | 
                               SmartPtr<V4l2SubDevice> isp_dev) 
 | 
{ 
 | 
    _isp_core_dev = isp_dev; 
 | 
    for (int i = 0; i < 3; i++) { 
 | 
        _isp_mipi_tx_infos[i].dev = mipi_tx_devs[i]; 
 | 
        _isp_mipi_rx_infos[i].dev = mipi_rx_devs[i]; 
 | 
    } 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::set_hdr_frame_readback_infos(rk_aiq_luma_params_t luma_params) 
 | 
{ 
 | 
    _mipi_trigger_mutex.lock(); 
 | 
    _isp_hdr_fid2times_map[luma_params.frame_id] = luma_params; 
 | 
    LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "rdtimes seq %d \n", luma_params.frame_id); 
 | 
    _mipi_trigger_mutex.unlock(); 
 | 
    trigger_readback(); 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::create_stop_fds_mipi () { 
 | 
    int i, status = 0; 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
  
 | 
    destroy_stop_fds_mipi(); 
 | 
  
 | 
    for (i = 0; i < _mipi_dev_max; i++) { 
 | 
        status = pipe(_isp_mipi_tx_infos[i].stop_fds); 
 | 
        if (status < 0) { 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Failed to create mipi tx:%d poll stop pipe: %s", 
 | 
                            i, strerror(errno)); 
 | 
            ret = XCAM_RETURN_ERROR_UNKNOWN; 
 | 
            goto exit_error; 
 | 
        } 
 | 
        status = fcntl(_isp_mipi_tx_infos[0].stop_fds[0], F_SETFL, O_NONBLOCK); 
 | 
        if (status < 0) { 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Fail to set event mipi tx:%d stop pipe flag: %s", 
 | 
                            i, strerror(errno)); 
 | 
            goto exit_error; 
 | 
        } 
 | 
  
 | 
        status = pipe(_isp_mipi_rx_infos[i].stop_fds); 
 | 
        if (status < 0) { 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Failed to create mipi rx:%d poll stop pipe: %s", 
 | 
                            i, strerror(errno)); 
 | 
            ret = XCAM_RETURN_ERROR_UNKNOWN; 
 | 
            goto exit_error; 
 | 
        } 
 | 
        status = fcntl(_isp_mipi_rx_infos[0].stop_fds[0], F_SETFL, O_NONBLOCK); 
 | 
        if (status < 0) { 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Fail to set event mipi rx:%d stop pipe flag: %s", 
 | 
                            i, strerror(errno)); 
 | 
            goto exit_error; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
exit_error: 
 | 
    destroy_stop_fds_mipi(); 
 | 
    return ret; 
 | 
} 
 | 
  
 | 
void Isp20PollThread::destroy_stop_fds_mipi () { 
 | 
    for (int i = 0; i < 3; i++) { 
 | 
        if (_isp_mipi_tx_infos[i].stop_fds[0] != -1 || 
 | 
                _isp_mipi_tx_infos[i].stop_fds[1] != -1) { 
 | 
            close(_isp_mipi_tx_infos[i].stop_fds[0]); 
 | 
            close(_isp_mipi_tx_infos[i].stop_fds[1]); 
 | 
            _isp_mipi_tx_infos[i].stop_fds[0] = -1; 
 | 
            _isp_mipi_tx_infos[i].stop_fds[1] = -1; 
 | 
        } 
 | 
  
 | 
        if (_isp_mipi_rx_infos[i].stop_fds[0] != -1 || 
 | 
                _isp_mipi_rx_infos[i].stop_fds[1] != -1) { 
 | 
            close(_isp_mipi_rx_infos[i].stop_fds[0]); 
 | 
            close(_isp_mipi_rx_infos[i].stop_fds[1]); 
 | 
            _isp_mipi_rx_infos[i].stop_fds[0] = -1; 
 | 
            _isp_mipi_rx_infos[i].stop_fds[1] = -1; 
 | 
        } 
 | 
    } 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::mipi_poll_buffer_loop (int type, int dev_index) 
 | 
{ 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
    int poll_ret = 0; 
 | 
    SmartPtr<V4l2Buffer> buf; 
 | 
    SmartPtr<V4l2Device> dev; 
 | 
    int stop_fd = -1; 
 | 
  
 | 
    if (type == ISP_POLL_MIPI_TX) { 
 | 
        dev = _isp_mipi_tx_infos[dev_index].dev; 
 | 
        stop_fd = _isp_mipi_tx_infos[dev_index].stop_fds[0]; 
 | 
    } else if (type == ISP_POLL_MIPI_RX) { 
 | 
        dev = _isp_mipi_rx_infos[dev_index].dev; 
 | 
        stop_fd = _isp_mipi_rx_infos[dev_index].stop_fds[0]; 
 | 
    } else 
 | 
        return XCAM_RETURN_ERROR_UNKNOWN; 
 | 
  
 | 
    poll_ret = dev->poll_event (PollThread::default_poll_timeout, 
 | 
                                stop_fd); 
 | 
  
 | 
    if (poll_ret == POLL_STOP_RET) { 
 | 
        LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "poll %s buffer stop success !", mipi_poll_type_to_str[type]); 
 | 
        // stop success, return error to stop the poll thread 
 | 
        return XCAM_RETURN_ERROR_UNKNOWN; 
 | 
    } 
 | 
  
 | 
    if (poll_ret <= 0) { 
 | 
        LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "mipi_dev_index %d poll %s buffer event got error(0x%x) but continue\n", 
 | 
                        dev_index, mipi_poll_type_to_str[type], poll_ret); 
 | 
        ::usleep (10000); // 10ms 
 | 
        return XCAM_RETURN_ERROR_TIMEOUT; 
 | 
    } 
 | 
  
 | 
    ret = dev->dequeue_buffer (buf); 
 | 
    if (ret != XCAM_RETURN_NO_ERROR) { 
 | 
        LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "dequeue %s buffer failed", mipi_poll_type_to_str[type]); 
 | 
        return ret; 
 | 
    } 
 | 
  
 | 
    SmartPtr<V4l2BufferProxy> buf_proxy = new V4l2BufferProxy(buf, dev); 
 | 
    if (type == ISP_POLL_MIPI_TX) { 
 | 
        handle_tx_buf(buf_proxy, dev_index); 
 | 
    } else if (type == ISP_POLL_MIPI_RX) { 
 | 
        _event_handle_dev->on_dqueue(dev_index, buf_proxy); 
 | 
        handle_rx_buf(buf_proxy, dev_index); 
 | 
    } 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::handle_rx_buf(SmartPtr<V4l2BufferProxy> &rx_buf, int dev_index) 
 | 
{ 
 | 
    if (!_isp_mipi_rx_infos[dev_index].buf_list.is_empty()) { 
 | 
        SmartPtr<V4l2BufferProxy> buf = _isp_mipi_rx_infos[dev_index].buf_list.pop(-1); 
 | 
        LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "%s dev_index:%d index:%d fd:%d\n", 
 | 
                        __func__, dev_index, buf->get_v4l2_buf_index(), buf->get_expbuf_fd()); 
 | 
    } 
 | 
} 
 | 
  
 | 
void Isp20PollThread::sync_tx_buf() 
 | 
{ 
 | 
    SmartPtr<V4l2BufferProxy> buf_s, buf_m, buf_l; 
 | 
    uint32_t sequence_s = -1, sequence_m = -1, sequence_l = -1; 
 | 
  
 | 
    _mipi_buf_mutex.lock(); 
 | 
    for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
        if (_isp_mipi_tx_infos[i].buf_list.is_empty()) { 
 | 
            _mipi_buf_mutex.unlock(); 
 | 
            return; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    buf_l = _isp_mipi_tx_infos[ISP_MIPI_HDR_L].buf_list.front(); 
 | 
    if (buf_l.ptr()) 
 | 
        sequence_l = buf_l->get_sequence(); 
 | 
  
 | 
    buf_m = _isp_mipi_tx_infos[ISP_MIPI_HDR_M].buf_list.front(); 
 | 
    if (buf_m.ptr()) 
 | 
        sequence_m = buf_m->get_sequence(); 
 | 
  
 | 
    buf_s = _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.front(); 
 | 
  
 | 
    if (buf_s.ptr()) { 
 | 
        sequence_s = buf_s->get_sequence(); 
 | 
        if ((_working_mode == RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR || 
 | 
                _working_mode == RK_AIQ_ISP_HDR_MODE_3_LINE_HDR) && 
 | 
                buf_m.ptr() && buf_l.ptr() && buf_s.ptr() && 
 | 
                sequence_l == sequence_s && sequence_m == sequence_s) { 
 | 
  
 | 
            _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.erase(buf_s); 
 | 
            _isp_mipi_tx_infos[ISP_MIPI_HDR_M].buf_list.erase(buf_m); 
 | 
            _isp_mipi_tx_infos[ISP_MIPI_HDR_L].buf_list.erase(buf_l); 
 | 
            if (check_skip_frame(sequence_s)) { 
 | 
                LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "skip frame %d", sequence_s); 
 | 
                goto end; 
 | 
            } 
 | 
            _isp_mipi_rx_infos[ISP_MIPI_HDR_S].cache_list.push(buf_s); 
 | 
            _isp_mipi_rx_infos[ISP_MIPI_HDR_M].cache_list.push(buf_m); 
 | 
            _isp_mipi_rx_infos[ISP_MIPI_HDR_L].cache_list.push(buf_l); 
 | 
            _mipi_trigger_mutex.lock(); 
 | 
            _isp_hdr_fid2ready_map[sequence_s] = true; 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "trigger readback %d", sequence_s); 
 | 
            trigger_readback(); 
 | 
        } else if ((_working_mode == RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR || 
 | 
                    _working_mode == RK_AIQ_ISP_HDR_MODE_2_LINE_HDR) && 
 | 
                   buf_m.ptr() && buf_s.ptr() && sequence_m == sequence_s) { 
 | 
            _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.erase(buf_s); 
 | 
            _isp_mipi_tx_infos[ISP_MIPI_HDR_M].buf_list.erase(buf_m); 
 | 
            if (check_skip_frame(sequence_s)) { 
 | 
                LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "skip frame %d", sequence_s); 
 | 
                goto end; 
 | 
            } 
 | 
            _isp_mipi_rx_infos[ISP_MIPI_HDR_S].cache_list.push(buf_s); 
 | 
            _isp_mipi_rx_infos[ISP_MIPI_HDR_M].cache_list.push(buf_m); 
 | 
            _mipi_trigger_mutex.lock(); 
 | 
            _isp_hdr_fid2ready_map[sequence_s] = true; 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "trigger readback %d", sequence_s); 
 | 
            trigger_readback(); 
 | 
        } else if (_working_mode == RK_AIQ_WORKING_MODE_NORMAL) { 
 | 
            _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.erase(buf_s); 
 | 
            if (check_skip_frame(sequence_s)) { 
 | 
                LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "skip frame %d", sequence_s); 
 | 
                goto end; 
 | 
            } 
 | 
            _isp_mipi_rx_infos[ISP_MIPI_HDR_S].cache_list.push(buf_s); 
 | 
            _mipi_trigger_mutex.lock(); 
 | 
            _isp_hdr_fid2ready_map[sequence_s] = true; 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "trigger readback %d", sequence_s); 
 | 
            trigger_readback(); 
 | 
        } else { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "do nothing, sequence not match l: %d, s: %d, m: %d !!!", 
 | 
                            sequence_l, sequence_s, sequence_m); 
 | 
        } 
 | 
    } 
 | 
end: 
 | 
    _mipi_buf_mutex.unlock(); 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::handle_tx_buf(SmartPtr<V4l2BufferProxy> &tx_buf, int dev_index) 
 | 
{ 
 | 
    LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "%s dev_index:%d sequence:%d\n", 
 | 
                    __func__, dev_index, tx_buf->get_sequence()); 
 | 
    _isp_mipi_tx_infos[dev_index].buf_list.push(tx_buf); 
 | 
    sync_tx_buf(); 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::trigger_readback() 
 | 
{ 
 | 
    std::map<uint32_t, bool>::iterator it_ready; 
 | 
    SmartPtr<V4l2Buffer> v4l2buf[3]; 
 | 
    SmartPtr<V4l2BufferProxy> buf_proxy; 
 | 
    uint32_t sequence = -1; 
 | 
    sint32_t additional_times = -1; 
 | 
    bool isHdrGlobalTmo = false; 
 | 
    bool isDhazEn = false, isTmoEn = false; 
 | 
    u64 ispModuleEns = 0x0; 
 | 
  
 | 
    _mipi_trigger_mutex.lock(); 
 | 
  
 | 
    if (!_first_trigger && _cache_tx_data) { 
 | 
        /* 
 | 
         * The hdrtmo needs to get the luma in advance, 
 | 
         * so cache a frame of tx data. 
 | 
         */ 
 | 
        if (_isp_hdr_fid2ready_map.size() < 2) { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s buf not ready(%d) !", 
 | 
                    __func__, _isp_hdr_fid2ready_map.size()); 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            return; 
 | 
        } 
 | 
    } else { 
 | 
        if (_isp_hdr_fid2ready_map.size() == 0) { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s buf not ready(%d) !", 
 | 
                    __func__, _isp_hdr_fid2ready_map.size()); 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            return; 
 | 
        } 
 | 
    } 
 | 
    it_ready = _isp_hdr_fid2ready_map.begin(); 
 | 
    sequence = it_ready->first; 
 | 
  
 | 
    if (!_event_handle_dev->is_virtual_sensor()) { 
 | 
        match_lumadetect_map(sequence, additional_times); 
 | 
        if (additional_times == -1) { 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, 
 | 
                            "%s rdtimes not ready for seq %d !", 
 | 
                            __func__, sequence); 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            return; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    match_globaltmostate_map(sequence, isHdrGlobalTmo); 
 | 
    _isp_hdr_fid2ready_map.erase(it_ready); 
 | 
  
 | 
    if (mCamHw) { 
 | 
        int ret = XCAM_RETURN_NO_ERROR; 
 | 
  
 | 
        if (ret != XCAM_RETURN_NO_ERROR) { 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, 
 | 
                            "%s frame[%d] set isp params failed, don't read back!\n", 
 | 
                            __func__, sequence); 
 | 
            // drop frame, return buf to tx 
 | 
            for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
                _isp_mipi_rx_infos[i].cache_list.pop(-1); 
 | 
            } 
 | 
            goto out; 
 | 
        } else { 
 | 
            // whether to start capturing raw files 
 | 
            char file_name[32] = {0}; 
 | 
            snprintf(file_name, sizeof(file_name), "%s", CAPTURE_CNT_FILENAME); 
 | 
            detect_capture_raw_status(file_name, sequence); 
 | 
  
 | 
            for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
                ret = _isp_mipi_rx_infos[i].dev->get_buffer(v4l2buf[i], 
 | 
                        _isp_mipi_rx_infos[i].cache_list.front()->get_v4l2_buf_index()); 
 | 
                if (ret != XCAM_RETURN_NO_ERROR) { 
 | 
                    LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Rx[%d] can not get buffer\n", i); 
 | 
                    goto out; 
 | 
                } else { 
 | 
                    buf_proxy = _isp_mipi_rx_infos[i].cache_list.pop(-1); 
 | 
#if 0 
 | 
                    if (_first_trigger) { 
 | 
                        u8 *buf = (u8 *)buf_proxy->get_v4l2_userptr(); 
 | 
                        struct v4l2_format format = v4l2buf[i]->get_format(); 
 | 
                        u32 bytesperline = format.fmt.pix_mp.plane_fmt[0].bytesperline; 
 | 
  
 | 
                        if (buf) { 
 | 
                            for (u32 k = 0; k < 16; k++) { 
 | 
                                for (u32 j = 0; j < bytesperline / 2; j++) 
 | 
                                    *buf++ += (k + j) % 16; 
 | 
                                buf += bytesperline / 2; 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
#endif 
 | 
                    _isp_mipi_rx_infos[i].buf_list.push(buf_proxy); 
 | 
                    if (_isp_mipi_rx_infos[i].dev->get_mem_type() == V4L2_MEMORY_USERPTR) 
 | 
                        v4l2buf[i]->set_expbuf_usrptr(buf_proxy->get_v4l2_userptr()); 
 | 
                    else if (_isp_mipi_rx_infos[i].dev->get_mem_type() == V4L2_MEMORY_DMABUF){ 
 | 
                        v4l2buf[i]->set_expbuf_fd(buf_proxy->get_expbuf_fd()); 
 | 
                    }else if (_isp_mipi_rx_infos[i].dev->get_mem_type() == V4L2_MEMORY_MMAP) { 
 | 
                        if (_isp_mipi_tx_infos[i].dev->get_use_type() == 1) 
 | 
                        { 
 | 
                            memcpy((void*)v4l2buf[i]->get_expbuf_usrptr(),(void*)buf_proxy->get_v4l2_userptr(),v4l2buf[i]->get_buf().m.planes[0].length); 
 | 
                            v4l2buf[i]->set_reserved(buf_proxy->get_v4l2_userptr()); 
 | 
                        } 
 | 
                    } 
 | 
  
 | 
                    dynamic_capture_raw(i, sequence, buf_proxy, v4l2buf[i]); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            for (int i = 0; i < _mipi_dev_max; i++) { 
 | 
                ret = _isp_mipi_rx_infos[i].dev->queue_buffer(v4l2buf[i]); 
 | 
                if (ret != XCAM_RETURN_NO_ERROR) { 
 | 
                    _isp_mipi_rx_infos[i].buf_list.pop(-1); 
 | 
                    LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Rx[%d] queue buffer failed\n", i); 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
  
 | 
            struct isp2x_csi_trigger tg = { 
 | 
                .sof_timestamp = 0, 
 | 
                .frame_timestamp = 0, 
 | 
                .frame_id = sequence, 
 | 
                .times = 0, 
 | 
                .mode = _mipi_dev_max == 1 ? T_START_X1 : 
 | 
                _mipi_dev_max == 2 ? T_START_X2 : T_START_X3, 
 | 
                /* .mode = T_START_X2, */ 
 | 
            }; 
 | 
  
 | 
            ispModuleEns = mCamHw->getIspModuleEnState(); 
 | 
            if (ispModuleEns & (1LL <<  RK_ISP2X_HDRTMO_ID)) 
 | 
                isTmoEn = true; 
 | 
            if (ispModuleEns & (1LL << RK_ISP2X_DHAZ_ID)) 
 | 
                isDhazEn = true; 
 | 
            /* In the case of multiple sensors, read back at least twice 
 | 
             * if dhaz or tmo enable 
 | 
             */ 
 | 
            if (_is_multi_cam_conc && (isTmoEn || isDhazEn)) 
 | 
                tg.times = 1; 
 | 
  
 | 
            /* Fixed read back once: 
 | 
             * 1. global TMO and dhaz is off 
 | 
             * 2. tmo && dhaz is off 
 | 
             */ 
 | 
            if (isTmoEn && isHdrGlobalTmo && !isDhazEn) 
 | 
                additional_times = 0; 
 | 
            else if (!isTmoEn && !isDhazEn) 
 | 
                additional_times = 0; 
 | 
  
 | 
            tg.times += additional_times; 
 | 
  
 | 
            if (_first_trigger) 
 | 
                tg.times = 1; 
 | 
            else if (tg.times > 2) 
 | 
                tg.times = 2; 
 | 
  
 | 
            uint64_t sof_timestamp; 
 | 
            match_sof_timestamp_map(tg.frame_id, sof_timestamp); 
 | 
            tg.sof_timestamp = sof_timestamp; 
 | 
            tg.frame_timestamp = buf_proxy->get_timestamp () * 1000; 
 | 
            // tg.times = 1;//fixed to three times readback 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, 
 | 
                            "frame[%d]: sof_ts %" PRId64 "ms, frame_ts %" PRId64 "ms, globalTmo(%d), readback(%d)\n", 
 | 
                            sequence, 
 | 
                            tg.sof_timestamp / 1000 / 1000, 
 | 
                            tg.frame_timestamp / 1000 / 1000, 
 | 
                            isHdrGlobalTmo, 
 | 
                            tg.times); 
 | 
  
 | 
            if (ret == XCAM_RETURN_NO_ERROR) 
 | 
                _isp_core_dev->io_control(RKISP_CMD_TRIGGER_READ_BACK, &tg); 
 | 
            else 
 | 
                LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "%s frame[%d] queue  failed, don't read back!\n", 
 | 
                                __func__, sequence); 
 | 
  
 | 
            update_capture_raw_status(file_name); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    _first_trigger = false; 
 | 
out: 
 | 
    _mipi_trigger_mutex.unlock(); 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::getEffectiveLumaParams(int frame_id, rk_aiq_luma_params_t& luma_params) 
 | 
{ 
 | 
    ENTER_CAMHW_FUNCTION(); 
 | 
    std::map<uint32_t, rk_aiq_luma_params_t>::iterator it; 
 | 
    uint32_t search_id = frame_id < 0 ? 0 : frame_id; 
 | 
  
 | 
    if (_isp_hdr_fid2times_map.size() == 0) { 
 | 
        LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "can't search id %d,  _effecting_exp_mapsize is %d\n", 
 | 
                        frame_id, _isp_hdr_fid2times_map.size()); 
 | 
        return  XCAM_RETURN_ERROR_PARAM; 
 | 
    } 
 | 
  
 | 
    it = _isp_hdr_fid2times_map.find(search_id); 
 | 
  
 | 
    // havn't found 
 | 
    if (it == _isp_hdr_fid2times_map.end()) { 
 | 
        std::map<uint32_t, rk_aiq_luma_params_t>::reverse_iterator rit; 
 | 
  
 | 
        rit = _isp_hdr_fid2times_map.rbegin(); 
 | 
        do { 
 | 
            if (search_id >= rit->first) { 
 | 
                LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "exp-sync: can't find id %d, get latest id %d in _isp_hdr_fid2times_map\n", 
 | 
                                search_id, rit->first); 
 | 
                break; 
 | 
            } 
 | 
        } while (++rit != _isp_hdr_fid2times_map.rend()); 
 | 
  
 | 
        if (rit == _isp_hdr_fid2times_map.rend()) { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "can't find the latest effecting exposure for id %d, impossible case !", frame_id); 
 | 
            return XCAM_RETURN_ERROR_PARAM; 
 | 
        } 
 | 
  
 | 
        luma_params = rit->second; 
 | 
    } else { 
 | 
        luma_params = it->second; 
 | 
    } 
 | 
  
 | 
    while (_isp_hdr_fid2times_map.size() > 4) 
 | 
        _isp_hdr_fid2times_map.erase(_isp_hdr_fid2times_map.begin()); 
 | 
  
 | 
    EXIT_CAMHW_FUNCTION(); 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::match_lumadetect_map(uint32_t sequence, sint32_t &additional_times) 
 | 
{ 
 | 
    uint32_t frame_id, target_id; 
 | 
  
 | 
    if (!_need_luma_rd_info) { 
 | 
        additional_times = 0; 
 | 
        return ; 
 | 
    } 
 | 
     
 | 
    if (_isp_hdr_fid2times_map.empty()) 
 | 
        LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "luma map is empty"); 
 | 
  
 | 
    while (_isp_hdr_fid2times_map.size() > 4) 
 | 
        _isp_hdr_fid2times_map.erase(_isp_hdr_fid2times_map.begin()); 
 | 
  
 | 
    std::map<uint32_t, rk_aiq_luma_params_t>::iterator iter, it_times_del; 
 | 
    for (iter = _isp_hdr_fid2times_map.begin(); iter != _isp_hdr_fid2times_map.end();) { 
 | 
        if (_cache_tx_data) { 
 | 
            /* 
 | 
             * The hdrtmo needs to get the luma in advance, 
 | 
             * so match the luma of previous frame in Lumadetect. 
 | 
             */ 
 | 
            target_id = iter->first - 1; 
 | 
        } else { 
 | 
            target_id = iter->first; 
 | 
        } 
 | 
  
 | 
        if (target_id < sequence && iter->first != 0) { 
 | 
            it_times_del = iter++; 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "del seq %d", it_times_del->first); 
 | 
            // _isp_hdr_fid2times_map.erase(it_times_del); 
 | 
        } else if (target_id == sequence || iter->first == 0) { 
 | 
            additional_times = iter->second.hdrProcessCnt; 
 | 
            frame_id = iter->first; 
 | 
            it_times_del = iter++; 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "find luma id(%d)-seq id(%d)", frame_id, sequence); 
 | 
            // _isp_hdr_fid2times_map.erase(it_times_del); 
 | 
            break; 
 | 
        } else { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, 
 | 
                    "%s missing rdtimes for buf_seq %d, min rdtimes_seq %d !", 
 | 
                    __func__, sequence, iter->first); 
 | 
            additional_times = 0; 
 | 
            break; 
 | 
        } 
 | 
    } 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::match_globaltmostate_map(uint32_t sequence, bool &isHdrGlobalTmo) 
 | 
{ 
 | 
    std::map<uint32_t, bool>::iterator it_del; 
 | 
    for (std::map<uint32_t, bool>::iterator iter = _hdr_global_tmo_state_map.begin(); 
 | 
            iter !=  _hdr_global_tmo_state_map.end();) { 
 | 
        if (iter->first < sequence) { 
 | 
            it_del = iter++; 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "del seq %d", it_del->first); 
 | 
            _hdr_global_tmo_state_map.erase(it_del); 
 | 
        } else if (iter->first == sequence) { 
 | 
            isHdrGlobalTmo = iter->second; 
 | 
            it_del = iter++; 
 | 
            LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "del seq %d", it_del->first); 
 | 
            _hdr_global_tmo_state_map.erase(it_del); 
 | 
            break; 
 | 
        } else { 
 | 
            LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s missing tmo state for buf_seq %d, min rdtimes_seq %d !", 
 | 
                            __func__, sequence, iter->first); 
 | 
            break; 
 | 
        } 
 | 
    } 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::match_sof_timestamp_map(sint32_t sequence, uint64_t ×tamp) 
 | 
{ 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
    std::map<int, uint64_t>::iterator it; 
 | 
    sint32_t search_id = sequence < 0 ? 0 : sequence; 
 | 
  
 | 
    _sof_map_mutex.lock(); 
 | 
    it = _sof_timestamp_map.find(search_id); 
 | 
    if (it != _sof_timestamp_map.end()) { 
 | 
        timestamp = it->second; 
 | 
        _sof_timestamp_map.erase(it); 
 | 
    } else { 
 | 
        LOGW_CAMHW_SUBM(ISP20POLL_SUBM, 
 | 
                "can't find frameid(%d), get sof timestamp failed!\n", 
 | 
                sequence); 
 | 
        ret = XCAM_RETURN_ERROR_FAILED; 
 | 
    } 
 | 
    _sof_map_mutex.unlock(); 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::write_metadata_to_file(const char* dir_path, 
 | 
                                        int frame_id, 
 | 
                                        rkisp_effect_params_v20& ispParams, 
 | 
                                        SmartPtr<RkAiqExpParamsProxy>& expParams, 
 | 
                                        SmartPtr<RkAiqAfInfoProxy>& afParams) 
 | 
{ 
 | 
#if 0 // TODO Merge 
 | 
    FILE *fp = nullptr; 
 | 
    char file_name[64] = {0}; 
 | 
    char buffer[256] = {0}; 
 | 
    int32_t focusCode = 0; 
 | 
    int32_t zoomCode = 0; 
 | 
  
 | 
    snprintf(file_name, sizeof(file_name), "%s/meta_data", dir_path); 
 | 
  
 | 
    if(afParams.ptr()) { 
 | 
        focusCode = afParams->data()->focusCode; 
 | 
        zoomCode = afParams->data()->zoomCode; 
 | 
    } 
 | 
  
 | 
    fp = fopen(file_name, "ab+"); 
 | 
    if (fp != nullptr) { 
 | 
        if (_working_mode == RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR || \ 
 | 
                _working_mode == RK_AIQ_ISP_HDR_MODE_3_LINE_HDR) { 
 | 
            snprintf(buffer, 
 | 
                     sizeof(buffer), 
 | 
                     "frame%08d-l_m_s-gain[%08.5f_%08.5f_%08.5f]-time[%08.5f_%08.5f_%08.5f]-" 
 | 
                     "awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]-afcode[%08d_%08d]\n", 
 | 
                     frame_id, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[2].exp_real_params.analog_gain, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.analog_gain, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.analog_gain, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[2].exp_real_params.integration_time, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.integration_time, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.integration_time, 
 | 
                     ispParams->data()->awb_gain.rgain, 
 | 
                     ispParams->data()->awb_gain.grgain, 
 | 
                     ispParams->data()->awb_gain.gbgain, 
 | 
                     ispParams->data()->awb_gain.bgain, 
 | 
                     1, 
 | 
                     focusCode, 
 | 
                     zoomCode); 
 | 
        } else if (_working_mode == RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR || \ 
 | 
                   _working_mode == RK_AIQ_ISP_HDR_MODE_2_LINE_HDR) { 
 | 
            snprintf(buffer, 
 | 
                     sizeof(buffer), 
 | 
                     "frame%08d-l_s-gain[%08.5f_%08.5f]-time[%08.5f_%08.5f]-" 
 | 
                     "awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]-afcode[%08d_%08d]\n", 
 | 
                     frame_id, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.analog_gain, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.analog_gain, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.integration_time, 
 | 
                     expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.integration_time, 
 | 
                     ispParams->data()->awb_gain.rgain, 
 | 
                     ispParams->data()->awb_gain.grgain, 
 | 
                     ispParams->data()->awb_gain.gbgain, 
 | 
                     ispParams->data()->awb_gain.bgain, 
 | 
                     1, 
 | 
                     focusCode, 
 | 
                     zoomCode); 
 | 
        } else { 
 | 
            snprintf(buffer, 
 | 
                     sizeof(buffer), 
 | 
                     "frame%08d-gain[%08.5f]-time[%08.5f]-" 
 | 
                     "awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]-afcode[%08d_%08d]\n", 
 | 
                     frame_id, 
 | 
                     expParams->data()->aecExpInfo.LinearExp.exp_real_params.analog_gain, 
 | 
                     expParams->data()->aecExpInfo.LinearExp.exp_real_params.integration_time, 
 | 
                     ispParams->data()->awb_gain.rgain, 
 | 
                     ispParams->data()->awb_gain.grgain, 
 | 
                     ispParams->data()->awb_gain.gbgain, 
 | 
                     ispParams->data()->awb_gain.bgain, 
 | 
                     1, 
 | 
                     focusCode, 
 | 
                     zoomCode); 
 | 
        } 
 | 
  
 | 
        fwrite((void *)buffer, strlen(buffer), 1, fp); 
 | 
        fflush(fp); 
 | 
        fclose(fp); 
 | 
    } 
 | 
#endif 
 | 
} 
 | 
  
 | 
const struct capture_fmt* Isp20PollThread::find_fmt(const uint32_t pixelformat) 
 | 
{ 
 | 
    const struct capture_fmt *fmt; 
 | 
    unsigned int i; 
 | 
  
 | 
    for (i = 0; i < sizeof(csirx_fmts); i++) { 
 | 
        fmt = &csirx_fmts[i]; 
 | 
        if (fmt->fourcc == pixelformat) 
 | 
            return fmt; 
 | 
    } 
 | 
  
 | 
    return NULL; 
 | 
} 
 | 
  
 | 
int Isp20PollThread::detect_capture_raw_status(const char* file_name, uint32_t sequence) 
 | 
{ 
 | 
    if (!_is_capture_raw) { 
 | 
        uint32_t rawFrmId = 0; 
 | 
        get_value_from_file(file_name, _capture_raw_num, rawFrmId); 
 | 
  
 | 
        if (_capture_raw_num > 0) { 
 | 
            set_value_to_file(file_name, _capture_raw_num, sequence); 
 | 
            _is_capture_raw = true; 
 | 
            _capture_metadata_num = _capture_raw_num; 
 | 
            if (_first_trigger) 
 | 
                ++_capture_metadata_num; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
int Isp20PollThread::update_capture_raw_status(const char* file_name) 
 | 
{ 
 | 
    if (_is_capture_raw && !_first_trigger) { 
 | 
        if (_capture_raw_type == CAPTURE_RAW_AND_YUV_SYNC) { 
 | 
            _capture_image_mutex.lock(); 
 | 
            _capture_image_cond.timedwait(_capture_image_mutex, 3000000); 
 | 
            _capture_image_mutex.unlock(); 
 | 
        } 
 | 
  
 | 
        if (!--_capture_raw_num) { 
 | 
            set_value_to_file(file_name, _capture_raw_num); 
 | 
            _is_capture_raw = false; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
int Isp20PollThread::dynamic_capture_raw(int i, uint32_t sequence, 
 | 
        SmartPtr<V4l2BufferProxy> buf_proxy, 
 | 
        SmartPtr<V4l2Buffer> &v4l2buf) 
 | 
{ 
 | 
    if (_is_capture_raw && _capture_raw_num > 0) { 
 | 
        if (!_is_raw_dir_exist) { 
 | 
            if (_capture_raw_type == CAPTURE_RAW_SYNC) 
 | 
                creat_raw_dir(user_set_raw_dir); 
 | 
            else 
 | 
                creat_raw_dir(DEFAULT_CAPTURE_RAW_PATH); 
 | 
        } 
 | 
  
 | 
        if (_is_raw_dir_exist) { 
 | 
            char raw_name[128] = {0}; 
 | 
            FILE *fp = nullptr; 
 | 
  
 | 
            XCAM_STATIC_PROFILING_START(write_raw); 
 | 
            memset(raw_name, 0, sizeof(raw_name)); 
 | 
            if (_mipi_dev_max == 1) 
 | 
                snprintf(raw_name, sizeof(raw_name), 
 | 
                         "%s/frame%d_%dx%d_%s.raw", 
 | 
                         raw_dir_path, 
 | 
                         sequence, 
 | 
                         sns_width, 
 | 
                         sns_height, 
 | 
                         "normal"); 
 | 
            else if (_mipi_dev_max == 2) 
 | 
                snprintf(raw_name, sizeof(raw_name), 
 | 
                         "%s/frame%d_%dx%d_%s.raw", 
 | 
                         raw_dir_path, 
 | 
                         sequence, 
 | 
                         sns_width, 
 | 
                         sns_height, 
 | 
                         i == 0 ? "short" : "long"); 
 | 
            else 
 | 
                snprintf(raw_name, sizeof(raw_name), 
 | 
                         "%s/frame%d_%dx%d_%s.raw", 
 | 
                         raw_dir_path, 
 | 
                         sequence, 
 | 
                         sns_width, 
 | 
                         sns_height, 
 | 
                         i == 0 ? "short" : i == 1 ? "middle" : "long"); 
 | 
  
 | 
            fp = fopen(raw_name, "wb+"); 
 | 
            if (fp != nullptr) { 
 | 
                int size = 0; 
 | 
#ifdef WRITE_RAW_FILE_HEADER 
 | 
                write_frame_header_to_raw(fp, i, sequence); 
 | 
#endif 
 | 
  
 | 
#if 0 
 | 
                size = v4l2buf->get_buf().m.planes[0].length; 
 | 
#else 
 | 
                /* raw image size compatible with ISP expansion line mode */ 
 | 
                size = _stride_perline * sns_height; 
 | 
#endif 
 | 
                write_raw_to_file(fp, i, sequence, 
 | 
                                  (void *)(buf_proxy->get_v4l2_userptr()), 
 | 
                                  size); 
 | 
                fclose(fp); 
 | 
            } 
 | 
            XCAM_STATIC_PROFILING_END(write_raw, 0); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
int Isp20PollThread::calculate_stride_per_line(const struct capture_fmt& fmt, 
 | 
        uint32_t& bytesPerLine) 
 | 
{ 
 | 
    uint32_t pixelsPerLine = 0, stridePerLine = 0; 
 | 
    /* The actual size stored in the memory */ 
 | 
    uint32_t actualBytesPerLine = 0; 
 | 
  
 | 
    bytesPerLine = sns_width * fmt.bpp[0] / 8; 
 | 
  
 | 
    pixelsPerLine = fmt.pcpp * DIV_ROUND_UP(sns_width, fmt.pcpp); 
 | 
    actualBytesPerLine = pixelsPerLine * fmt.bpp[0] / 8; 
 | 
  
 | 
#if 0 
 | 
    /* mipi wc(Word count) must be 4 byte aligned */ 
 | 
    stridePerLine = 256 * DIV_ROUND_UP(actualBytesPerLine, 256); 
 | 
#else 
 | 
    struct v4l2_format format; 
 | 
    memset(&format, 0, sizeof(format)); 
 | 
  
 | 
    _isp_mipi_tx_infos[0].dev->get_format(format); 
 | 
    stridePerLine = format.fmt.pix_mp.plane_fmt[0].bytesperline; 
 | 
#endif 
 | 
  
 | 
    LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "sns_width: %d, pixelsPerLine: %d, bytesPerLine: %d, stridePerLine: %d\n", 
 | 
                    sns_width, 
 | 
                    pixelsPerLine, 
 | 
                    bytesPerLine, 
 | 
                    stridePerLine); 
 | 
  
 | 
    return stridePerLine; 
 | 
} 
 | 
  
 | 
/* 
 | 
 * Refer to "Raw file structure" in the header of this file 
 | 
 */ 
 | 
XCamReturn 
 | 
Isp20PollThread::write_frame_header_to_raw(FILE *fp, int dev_index, 
 | 
        int sequence) 
 | 
{ 
 | 
    uint8_t buffer[128] = {0}; 
 | 
    uint32_t stridePerLine = 0, bytesPerLine = 0; 
 | 
    const struct capture_fmt* fmt = nullptr; 
 | 
    uint8_t mode = 0; 
 | 
    uint8_t frame_type = 0, storage_type = 0; 
 | 
  
 | 
    if (fp == nullptr) 
 | 
        return XCAM_RETURN_ERROR_PARAM; 
 | 
  
 | 
    if ((fmt = find_fmt(pixelformat))) 
 | 
        stridePerLine = calculate_stride_per_line(*fmt, bytesPerLine); 
 | 
  
 | 
    if (_working_mode == RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR || \ 
 | 
            _working_mode == RK_AIQ_ISP_HDR_MODE_3_LINE_HDR) { 
 | 
        mode = 3; 
 | 
        frame_type = dev_index == 0 ? 1 : dev_index == 1 ? 2 : 3; 
 | 
    } else if (_working_mode == RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR || \ 
 | 
               _working_mode == RK_AIQ_ISP_HDR_MODE_2_LINE_HDR) { 
 | 
        mode = 2; 
 | 
        frame_type = dev_index == 0 ? 1 : 3; 
 | 
    } else { 
 | 
        mode = 1; 
 | 
    } 
 | 
  
 | 
    _stride_perline = stridePerLine; 
 | 
  
 | 
    *((uint16_t* )buffer) = RAW_FILE_IDENT;   // Identifier 
 | 
    *((uint16_t* )(buffer + 2)) = HEADER_LEN;     // Header length 
 | 
    *((uint32_t* )(buffer + 4)) = sequence;   // Frame number 
 | 
    *((uint16_t* )(buffer + 8)) = sns_width;      // Image width 
 | 
    *((uint16_t* )(buffer + 10)) = sns_height;    // Image height 
 | 
    *(buffer + 12) = fmt->bpp[0];         // Bit depth 
 | 
    *(buffer + 13) = fmt->bayer_fmt;          // Bayer format 
 | 
    *(buffer + 14) = mode;            // Number of HDR frame 
 | 
    *(buffer + 15) = frame_type;          // Current frame type 
 | 
    *(buffer + 16) = storage_type;        // Storage type 
 | 
    *((uint16_t* )(buffer + 17)) = stridePerLine; // Line stride 
 | 
    *((uint16_t* )(buffer + 19)) = bytesPerLine;  // Effective line stride 
 | 
  
 | 
    fwrite(buffer, sizeof(buffer), 1, fp); 
 | 
    fflush(fp); 
 | 
  
 | 
    LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "frame%d: image rect: %dx%d, %d bit depth, Bayer fmt: %d, " 
 | 
                    "hdr frame number: %d, frame type: %d, Storage type: %d, " 
 | 
                    "line stride: %d, Effective line stride: %d\n", 
 | 
                    sequence, sns_width, sns_height, 
 | 
                    fmt->bpp[0], fmt->bayer_fmt, mode, 
 | 
                    frame_type, storage_type, stridePerLine, 
 | 
                    bytesPerLine); 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::write_raw_to_file(FILE* fp, int dev_index, 
 | 
                                   int sequence, void* userptr, int size) 
 | 
{ 
 | 
    if (fp == nullptr) 
 | 
        return XCAM_RETURN_ERROR_PARAM; 
 | 
  
 | 
    fwrite(userptr, size, 1, fp); 
 | 
    fflush(fp); 
 | 
  
 | 
    if (!dev_index) { 
 | 
        for (int i = 0; i < _capture_raw_num; i++) 
 | 
            printf(">"); 
 | 
        printf("\n"); 
 | 
  
 | 
        LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "write frame%d raw\n", sequence); 
 | 
    } 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::write_reg_to_file(uint32_t base_addr, uint32_t offset_addr, 
 | 
                                   int len, int sequence) 
 | 
{ 
 | 
  
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::creat_raw_dir(const char* path) 
 | 
{ 
 | 
    time_t now; 
 | 
    struct tm* timenow; 
 | 
  
 | 
    if (!path) 
 | 
        return XCAM_RETURN_ERROR_FAILED; 
 | 
  
 | 
    time(&now); 
 | 
    timenow = localtime(&now); 
 | 
  
 | 
    if (access(path, W_OK) == -1) { 
 | 
        if (mkdir(path, 0755) < 0) 
 | 
            LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "mkdir %s error(%s)!\n", 
 | 
                            path, strerror(errno)); 
 | 
        return XCAM_RETURN_ERROR_PARAM; 
 | 
    } 
 | 
  
 | 
    snprintf(raw_dir_path, sizeof(raw_dir_path), "%s/raw_%04d-%02d-%02d_%02d-%02d-%02d", 
 | 
             path, 
 | 
             timenow->tm_year + 1900, 
 | 
             timenow->tm_mon + 1, 
 | 
             timenow->tm_mday, 
 | 
             timenow->tm_hour, 
 | 
             timenow->tm_min, 
 | 
             timenow->tm_sec); 
 | 
  
 | 
    LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "mkdir %s for capturing %d frames raw!\n", 
 | 
                    raw_dir_path, _capture_raw_num); 
 | 
  
 | 
    if(mkdir(raw_dir_path, 0755) < 0) { 
 | 
        LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "mkdir %s error(%s)!!!\n", 
 | 
                        raw_dir_path, strerror(errno)); 
 | 
        return XCAM_RETURN_ERROR_PARAM; 
 | 
    } 
 | 
  
 | 
    _is_raw_dir_exist = true; 
 | 
  
 | 
    return XCAM_RETURN_ERROR_PARAM; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::notify_capture_raw() 
 | 
{ 
 | 
    SmartLock locker(_capture_image_mutex); 
 | 
    _capture_image_cond.broadcast(); 
 | 
  
 | 
    return XCAM_RETURN_NO_ERROR; 
 | 
} 
 | 
  
 | 
XCamReturn 
 | 
Isp20PollThread::capture_raw_ctl(capture_raw_t type, int count, const char* capture_dir, char* output_dir) 
 | 
{ 
 | 
    XCamReturn ret = XCAM_RETURN_NO_ERROR; 
 | 
  
 | 
    _capture_raw_type = type; 
 | 
    if (_capture_raw_type == CAPTURE_RAW_SYNC) { 
 | 
        if (capture_dir != nullptr) 
 | 
            snprintf(user_set_raw_dir, sizeof( user_set_raw_dir), 
 | 
                     "%s/capture_image", capture_dir); 
 | 
        else 
 | 
            strcpy(user_set_raw_dir, DEFAULT_CAPTURE_RAW_PATH); 
 | 
  
 | 
        char cmd_buffer[32] = {0}; 
 | 
        snprintf(cmd_buffer, sizeof(cmd_buffer), 
 | 
                 "echo %d > %s", 
 | 
                 count, CAPTURE_CNT_FILENAME); 
 | 
        system(cmd_buffer); 
 | 
  
 | 
        _capture_image_mutex.lock(); 
 | 
        if (_capture_image_cond.timedwait(_capture_image_mutex, 30000000) != 0) 
 | 
            ret = XCAM_RETURN_ERROR_TIMEOUT; 
 | 
        else 
 | 
            strncpy(output_dir, raw_dir_path, strlen(raw_dir_path)); 
 | 
        _capture_image_mutex.unlock(); 
 | 
    } else if (_capture_raw_type == CAPTURE_RAW_AND_YUV_SYNC) { 
 | 
        LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "capture raw and yuv images simultaneously!"); 
 | 
    } 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
void 
 | 
Isp20PollThread::set_hdr_global_tmo_mode(int frame_id, bool mode) 
 | 
{ 
 | 
    _mipi_trigger_mutex.lock(); 
 | 
    _hdr_global_tmo_state_map[frame_id] = mode; 
 | 
    _mipi_trigger_mutex.unlock(); 
 | 
} 
 | 
  
 | 
void Isp20PollThread::skip_frames(int skip_num, int32_t skip_seq) 
 | 
{ 
 | 
    _mipi_trigger_mutex.lock(); 
 | 
    _skip_num = skip_num; 
 | 
    _skip_to_seq = skip_seq + _skip_num; 
 | 
    _mipi_trigger_mutex.unlock(); 
 | 
} 
 | 
  
 | 
bool Isp20PollThread::check_skip_frame(int32_t buf_seq) 
 | 
{ 
 | 
    _mipi_trigger_mutex.lock(); 
 | 
#if 0 // ts 
 | 
    if (_skip_num > 0) { 
 | 
        int64_t skip_ts_ms = _skip_start_ts / 1000 / 1000; 
 | 
        int64_t buf_ts_ms = buf_ts / 1000; 
 | 
        LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "skip num  %d, start from %" PRId64 " ms,  buf ts %" PRId64 " ms", 
 | 
                        _skip_num, 
 | 
                        skip_ts_ms, 
 | 
                        buf_ts_ms); 
 | 
        if (buf_ts_ms  > skip_ts_ms) { 
 | 
            _skip_num--; 
 | 
            _mipi_trigger_mutex.unlock(); 
 | 
            return true; 
 | 
        } 
 | 
    } 
 | 
#else 
 | 
  
 | 
    if ((_skip_num > 0) && (buf_seq < _skip_to_seq)) { 
 | 
        LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "skip num  %d, skip seq %d, dest seq %d", 
 | 
                        _skip_num, buf_seq, _skip_to_seq); 
 | 
        _skip_num--; 
 | 
        _mipi_trigger_mutex.unlock(); 
 | 
        return true; 
 | 
    } 
 | 
#endif 
 | 
    _mipi_trigger_mutex.unlock(); 
 | 
    return false; 
 | 
} 
 | 
  
 | 
}; //namspace RkCam 
 |