/* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #ifndef _IA_CSS_CIRCBUF_H #define _IA_CSS_CIRCBUF_H #include #include #include #include #include #include "ia_css_circbuf_comm.h" #include "ia_css_circbuf_desc.h" /**************************************************************** * * Data structures. * ****************************************************************/ /** * @brief Data structure for the circular buffer. */ typedef struct ia_css_circbuf_s ia_css_circbuf_t; struct ia_css_circbuf_s { ia_css_circbuf_desc_t *desc; /* Pointer to the descriptor of the circbuf */ ia_css_circbuf_elem_t *elems; /* an array of elements */ }; /** * @brief Create the circular buffer. * * @param cb The pointer to the circular buffer. * @param elems An array of elements. * @param desc The descriptor set to the size using ia_css_circbuf_desc_init(). */ extern void ia_css_circbuf_create( ia_css_circbuf_t *cb, ia_css_circbuf_elem_t *elems, ia_css_circbuf_desc_t *desc); /** * @brief Destroy the circular buffer. * * @param cb The pointer to the circular buffer. */ extern void ia_css_circbuf_destroy( ia_css_circbuf_t *cb); /** * @brief Pop a value out of the circular buffer. * Get a value at the head of the circular buffer. * The user should call "ia_css_circbuf_is_empty()" * to avoid accessing to an empty buffer. * * @param cb The pointer to the circular buffer. * * @return the pop-out value. */ extern uint32_t ia_css_circbuf_pop( ia_css_circbuf_t *cb); /** * @brief Extract a value out of the circular buffer. * Get a value at an arbitrary poistion in the circular * buffer. The user should call "ia_css_circbuf_is_empty()" * to avoid accessing to an empty buffer. * * @param cb The pointer to the circular buffer. * @param offset The offset from "start" to the target position. * * @return the extracted value. */ extern uint32_t ia_css_circbuf_extract( ia_css_circbuf_t *cb, int offset); /**************************************************************** * * Inline functions. * ****************************************************************/ /** * @brief Set the "val" field in the element. * * @param elem The pointer to the element. * @param val The value to be set. */ static inline void ia_css_circbuf_elem_set_val( ia_css_circbuf_elem_t *elem, uint32_t val) { OP___assert(elem != NULL); elem->val = val; } /** * @brief Initialize the element. * * @param elem The pointer to the element. */ static inline void ia_css_circbuf_elem_init( ia_css_circbuf_elem_t *elem) { OP___assert(elem != NULL); ia_css_circbuf_elem_set_val(elem, 0); } /** * @brief Copy an element. * * @param src The element as the copy source. * @param dest The element as the copy destination. */ static inline void ia_css_circbuf_elem_cpy( ia_css_circbuf_elem_t *src, ia_css_circbuf_elem_t *dest) { OP___assert(src != NULL); OP___assert(dest != NULL); ia_css_circbuf_elem_set_val(dest, src->val); } /** * @brief Get position in the circular buffer. * * @param cb The pointer to the circular buffer. * @param base The base position. * @param offset The offset. * * @return the position at offset. */ static inline uint8_t ia_css_circbuf_get_pos_at_offset( ia_css_circbuf_t *cb, uint32_t base, int offset) { uint8_t dest; OP___assert(cb != NULL); OP___assert(cb->desc != NULL); OP___assert(cb->desc->size > 0); /* step 1: adjudst the offset */ while (offset < 0) { offset += cb->desc->size; } /* step 2: shift and round by the upper limit */ dest = OP_std_modadd(base, offset, cb->desc->size); return dest; } /** * @brief Get the offset between two positions in the circular buffer. * Get the offset from the source position to the terminal position, * along the direction in which the new elements come in. * * @param cb The pointer to the circular buffer. * @param src_pos The source position. * @param dest_pos The terminal position. * * @return the offset. */ static inline int ia_css_circbuf_get_offset( ia_css_circbuf_t *cb, uint32_t src_pos, uint32_t dest_pos) { int offset; OP___assert(cb != NULL); OP___assert(cb->desc != NULL); offset = (int)(dest_pos - src_pos); offset += (offset < 0) ? cb->desc->size : 0; return offset; } /** * @brief Get the maximum number of elements. * * @param cb The pointer to the circular buffer. * * @return the maximum number of elements. * * TODO: Test this API. */ static inline uint32_t ia_css_circbuf_get_size( ia_css_circbuf_t *cb) { OP___assert(cb != NULL); OP___assert(cb->desc != NULL); return cb->desc->size; } /** * @brief Get the number of available elements. * * @param cb The pointer to the circular buffer. * * @return the number of available elements. */ static inline uint32_t ia_css_circbuf_get_num_elems( ia_css_circbuf_t *cb) { int num; OP___assert(cb != NULL); OP___assert(cb->desc != NULL); num = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end); return (uint32_t)num; } /** * @brief Test if the circular buffer is empty. * * @param cb The pointer to the circular buffer. * * @return * - true when it is empty. * - false when it is not empty. */ static inline bool ia_css_circbuf_is_empty( ia_css_circbuf_t *cb) { OP___assert(cb != NULL); OP___assert(cb->desc != NULL); return ia_css_circbuf_desc_is_empty(cb->desc); } /** * @brief Test if the circular buffer is full. * * @param cb The pointer to the circular buffer. * * @return * - true when it is full. * - false when it is not full. */ static inline bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) { OP___assert(cb != NULL); OP___assert(cb->desc != NULL); return ia_css_circbuf_desc_is_full(cb->desc); } /** * @brief Write a new element into the circular buffer. * Write a new element WITHOUT checking whether the * circular buffer is full or not. So it also overwrites * the oldest element when the buffer is full. * * @param cb The pointer to the circular buffer. * @param elem The new element. */ static inline void ia_css_circbuf_write( ia_css_circbuf_t *cb, ia_css_circbuf_elem_t elem) { OP___assert(cb != NULL); OP___assert(cb->desc != NULL); /* Cannot continue as the queue is full*/ assert(!ia_css_circbuf_is_full(cb)); ia_css_circbuf_elem_cpy(&elem, &cb->elems[cb->desc->end]); cb->desc->end = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, 1); } /** * @brief Push a value in the circular buffer. * Put a new value at the tail of the circular buffer. * The user should call "ia_css_circbuf_is_full()" * to avoid accessing to a full buffer. * * @param cb The pointer to the circular buffer. * @param val The value to be pushed in. */ static inline void ia_css_circbuf_push( ia_css_circbuf_t *cb, uint32_t val) { ia_css_circbuf_elem_t elem; OP___assert(cb != NULL); /* set up an element */ ia_css_circbuf_elem_init(&elem); ia_css_circbuf_elem_set_val(&elem, val); /* write the element into the buffer */ ia_css_circbuf_write(cb, elem); } /** * @brief Get the number of free elements. * * @param cb The pointer to the circular buffer. * * @return: The number of free elements. */ static inline uint32_t ia_css_circbuf_get_free_elems( ia_css_circbuf_t *cb) { OP___assert(cb != NULL); OP___assert(cb->desc != NULL); return ia_css_circbuf_desc_get_free_elems(cb->desc); } /** * @brief Peek an element in Circular Buffer. * * @param cb The pointer to the circular buffer. * @param offset Offset to the element. * * @return the elements value. */ extern uint32_t ia_css_circbuf_peek( ia_css_circbuf_t *cb, int offset); /** * @brief Get an element in Circular Buffer. * * @param cb The pointer to the circular buffer. * @param offset Offset to the element. * * @return the elements value. */ extern uint32_t ia_css_circbuf_peek_from_start( ia_css_circbuf_t *cb, int offset); /** * @brief Increase Size of a Circular Buffer. * Use 'CAUTION' before using this function, This was added to * support / fix issue with increasing size for tagger only * * @param cb The pointer to the circular buffer. * @param sz_delta delta increase for new size * @param elems (optional) pointers to new additional elements * cb element array size will not be increased dynamically, * but new elements should be added at the end to existing * cb element array which if of max_size >= new size * * @return true on succesfully increasing the size * false on failure */ extern bool ia_css_circbuf_increase_size( ia_css_circbuf_t *cb, unsigned int sz_delta, ia_css_circbuf_elem_t *elems); #endif /*_IA_CSS_CIRCBUF_H */