diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index eeaeb98e9c..dd2947e749 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -42,6 +42,8 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ static esp_err_t s_del_csi_ctlr(csi_controller_t *ctlr); static esp_err_t s_ctlr_del(esp_cam_ctlr_t *cam_ctlr); static esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data); +static esp_err_t s_csi_ctlr_get_internal_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...); +static esp_err_t s_csi_ctlr_get_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len); static esp_err_t s_csi_ctlr_enable(esp_cam_ctlr_handle_t ctlr); static esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle); static esp_err_t s_ctlr_csi_stop(esp_cam_ctlr_handle_t handle); @@ -212,6 +214,8 @@ esp_err_t esp_cam_new_csi_ctlr(const esp_cam_ctlr_csi_config_t *config, esp_cam_ ctlr->base.disable = s_csi_ctlr_disable; ctlr->base.receive = s_ctlr_csi_receive; ctlr->base.register_event_callbacks = s_register_event_callbacks; + ctlr->base.get_internal_buffer = s_csi_ctlr_get_internal_buffer; + ctlr->base.get_buffer_len = s_csi_ctlr_get_buffer_length; *ret_handle = &(ctlr->base); @@ -256,6 +260,36 @@ static esp_err_t s_ctlr_del(esp_cam_ctlr_t *cam_ctlr) return ESP_OK; } +static esp_err_t s_csi_ctlr_get_internal_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...) +{ + csi_controller_t *csi_ctlr = __containerof(handle, csi_controller_t, base); + ESP_RETURN_ON_FALSE((csi_ctlr->csi_fsm >= CSI_FSM_INIT) && (csi_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver don't initialized or back_buffer not available"); + ESP_RETURN_ON_FALSE(fb_num && fb_num <= 1, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number"); + + csi_ctlr->bk_buffer_exposed = true; + const void **fb_itor = fb0; + va_list args; + va_start(args, fb0); + for (uint32_t i = 0; i < fb_num; i++) { + if (fb_itor) { + *fb_itor = csi_ctlr->backup_buffer; + fb_itor = va_arg(args, const void **); + } + } + va_end(args); + + return ESP_OK; +} + +static esp_err_t s_csi_ctlr_get_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len) +{ + csi_controller_t *csi_ctlr = __containerof(handle, csi_controller_t, base); + ESP_RETURN_ON_FALSE((csi_ctlr->csi_fsm >= CSI_FSM_INIT) && (csi_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver don't initialized or back_buffer not available"); + + *ret_fb_len = csi_ctlr->fb_size_in_bytes; + return ESP_OK; +} + static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) { bool need_yield = false; @@ -311,7 +345,7 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ dw_gdma_channel_config_transfer(chan, &csi_dma_transfer_config); dw_gdma_channel_enable_ctrl(chan, true); - if (ctlr->trans.buffer != ctlr->backup_buffer) { + if ((ctlr->trans.buffer != ctlr->backup_buffer) || ctlr->bk_buffer_exposed) { esp_err_t ret = esp_cache_msync((void *)(ctlr->trans.buffer), ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); assert(ret == ESP_OK); assert(ctlr->cbs.on_trans_finished); diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi_internal.h b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi_internal.h index ef488a5a29..7d9eb56fb5 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi_internal.h +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi_internal.h @@ -55,6 +55,7 @@ struct csi_controller_t { size_t fb_size_in_bytes; //Frame buffer size, in bytes esp_cam_ctlr_trans_t trans; //Saved done transaction to be given out to callers void *backup_buffer; //backup buffer to make csi bridge can work to avoid wrong state + bool bk_buffer_exposed; //status of if back_buffer is exposed to users QueueHandle_t trans_que; //transaction queue esp_cam_ctlr_evt_cbs_t cbs; //user callbacks void *cbs_user_data; //callback userdata diff --git a/components/esp_driver_cam/esp_cam_ctlr.c b/components/esp_driver_cam/esp_cam_ctlr.c index d2f4b3a94c..88c27822ff 100644 --- a/components/esp_driver_cam/esp_cam_ctlr.c +++ b/components/esp_driver_cam/esp_cam_ctlr.c @@ -64,6 +64,25 @@ esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, co return handle->register_event_callbacks(handle, cbs, user_data); } +esp_err_t esp_cam_ctlr_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); + ESP_RETURN_ON_FALSE(handle->get_internal_buffer, ESP_ERR_NOT_SUPPORTED, TAG, "get buffer function not supported"); + + va_list args; + va_start(args, fb0); + return handle->get_internal_buffer(handle, fb_num, fb0, args); + va_end(args); +} + +esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len) +{ + ESP_RETURN_ON_FALSE(handle && ret_fb_len, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle"); + ESP_RETURN_ON_FALSE(handle->get_buffer_len, ESP_ERR_NOT_SUPPORTED, TAG, "get buffer length function not supported"); + + return handle->get_buffer_len(handle, ret_fb_len); +} + esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle) { ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); diff --git a/components/esp_driver_cam/include/esp_cam_ctlr.h b/components/esp_driver_cam/include/esp_cam_ctlr.h index 85c85a7df2..3c7cbe2ae1 100644 --- a/components/esp_driver_cam/include/esp_cam_ctlr.h +++ b/components/esp_driver_cam/include/esp_cam_ctlr.h @@ -102,6 +102,36 @@ esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle); */ esp_err_t esp_cam_ctlr_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data); +/** + * @brief Get ESP CAM controller internal malloced backup buffer(s) addr + * + * @note Generally, data in internal buffer is ready when `on_trans_finished` event + * + * @param[in] handle ESP CAM controller handle + * @param[in] fb_num Number of frame buffer(s) to get. This value must be the same as the number of the followed fbN parameters + * @param[out] fb0 Address of the frame buffer 0 (first frame buffer) + * @param[out] ... List of other frame buffers if any + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid driver state + */ +esp_err_t esp_cam_ctlr_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...); + +/** + * @brief Get ESP CAM controller internal backup buffer length + * + * @param[in] handle ESP CAM controller handle + * @param[out] ret_fb_len Optional, The size of each frame buffer, in bytes. + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: NULL ptr + * - ESP_ERR_INVALID_STATE: Invalid driver state + */ +esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len); + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h b/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h index 2df5a500de..031b9f66da 100644 --- a/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h +++ b/components/esp_driver_cam/interface/esp_cam_ctlr_interface.h @@ -105,6 +105,34 @@ struct esp_cam_ctlr_t { */ esp_err_t (*register_event_callbacks)(esp_cam_ctlr_t *ctlr, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_ctx); + /** + * @brief Get ESP CAM controller internal malloced backup buffer(s) addr + * + * @param[in] esp_cam_ctlr_t * ESP CAM controller handle + * @param[in] uint32_t Number of frame buffer(s) to get. This value must be the same as the number of the followed fbN parameters + * @param[out] const void ** Address of the frame buffer 0 (first frame buffer) + * @param[out] ... List of other frame buffers if any + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid driver state + */ + esp_err_t (*get_internal_buffer)(esp_cam_ctlr_t *, uint32_t, const void **, ...); + + /** + * @brief Get ESP CAM controller internal backup buffer length + * + * @param[in] esp_cam_ctlr_t * ESP CAM controller handle + * @param[out] size_t * The size of each frame buffer, in bytes. + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: NULL ptr + * - ESP_ERR_INVALID_STATE: Invalid driver state + */ + esp_err_t (*get_buffer_len)(esp_cam_ctlr_t *, size_t *); + void *user_data; ///< User data }; diff --git a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c index 178016fef6..7b0e5db80e 100644 --- a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c +++ b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c @@ -25,5 +25,12 @@ TEST_CASE("TEST CSI driver allocation", "[csi]") esp_cam_ctlr_handle_t handle = NULL; TEST_ESP_OK(esp_cam_new_csi_ctlr(&csi_config, &handle)); TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_cam_new_csi_ctlr(&csi_config, &handle)); + + uint8_t *bk_buffer = NULL; + size_t bk_buffer_len = 0; + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer(handle, 1, (const void **)&bk_buffer)); + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len)); + TEST_ASSERT_NOT_NULL(bk_buffer); + TEST_ASSERT_EQUAL((csi_config.h_res * csi_config.v_res * 2), bk_buffer_len); // out type RGB565 using 2 byte / pixel TEST_ESP_OK(esp_cam_del_ctlr(handle)); }