WizziLab's serial protocol library
Dependents: modem_ref_helper_for_v5_3_217 modem_ref_helper
kal_buf_circ.cpp
- Committer:
- Jeej
- Date:
- 2022-03-10
- Revision:
- 17:8ce53c6e0350
- Parent:
- 10:c87566aded6e
File content as of revision 17:8ce53c6e0350:
/// @copyright /// ========================================================================={{{ /// Copyright (c) 2019 WizziLab / /// All rights reserved / /// / /// IMPORTANT: This Software may not be modified, copied or distributed unless / /// embedded on a WizziLab product. Other than for the foregoing purpose, this / /// Software and/or its documentation may not be used, reproduced, copied, / /// prepared derivative works of, modified, performed, distributed, displayed / /// or sold for any purpose. For the sole purpose of embedding this Software / /// on a WizziLab product, copy, modification and distribution of this / /// Software is granted provided that the following conditions are respected: / /// / /// * Redistributions of source code must retain the above copyright notice, / /// this list of conditions and the following disclaimer / /// / /// * Redistributions in binary form must reproduce the above copyright / /// notice, this list of conditions and the following disclaimer in the / /// documentation and/or other materials provided with the distribution. / /// / /// * The name of WizziLab can not be used to endorse or promote products / /// derived from this software without specific prior written permission. / /// / /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS / /// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED / /// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR / /// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR / /// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, / /// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, / /// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, / /// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY / /// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING / /// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS / /// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. / /// WIZZILAB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, / /// ENHANCEMENTS OR MODIFICATIONS. / /// / /// Should you have any questions regarding your right to use this Software, / /// contact WizziLab at www.wizzilab.com. / /// / /// =========================================================================}}} /// @endcopyright /// XXX: New code for reference. Still to be tested. #include "kal_buf_circ.h" #if defined(KAL_MALLOC) && defined(KAL_FREE) #ifndef CIRCULAR_BUFFER_MALLOC #define CIRCULAR_BUFFER_MALLOC(_s) KAL_MALLOC(_s) #endif #ifndef CIRCULAR_BUFFER_FREE #define CIRCULAR_BUFFER_FREE(_p) KAL_FREE(_p) #endif #define CIRCULAR_BUFFER_DYNAMIC #endif static __inline uint32_t kal_buf_circ_next_head(kal_buf_circ_static_handle_t* h, uint32_t nb_elements) { uint32_t next = h->head + (nb_elements * h->element_size); return (next >= h->max_length)? next - h->max_length : next; } static __inline uint32_t kal_buf_circ_next_tail(kal_buf_circ_static_handle_t* h, uint32_t nb_elements) { uint32_t next = h->tail + (nb_elements * h->element_size); return (next >= h->max_length)? next - h->max_length : next; } #ifdef CIRCULAR_BUFFER_DYNAMIC kal_buf_circ_handle_t kal_buf_circ_create(uint32_t nb_elements, uint32_t element_size) { // Malloc the h and the buffer kal_buf_circ_static_handle_t* h = CIRCULAR_BUFFER_MALLOC(sizeof(kal_buf_circ_static_handle_t)); h->buffer = (uint8_t*)CIRCULAR_BUFFER_MALLOC((nb_elements + 1) * element_size); h->head = 0; h->tail = 0; h->element_size = element_size; h->max_length = (nb_elements + 1) * element_size; h->is_static = false; return (kal_buf_circ_handle_t)h; } #endif int kal_buf_circ_create_static(kal_buf_circ_static_handle_t* static_handle, uint8_t* buffer, uint32_t nb_elements, uint32_t element_size) { // h and buffer are passed as parameters. kal_buf_circ_static_handle_t* h = static_handle; h->buffer = buffer; h->head = 0; h->tail = 0; h->element_size = element_size; h->max_length = (nb_elements + 1) * element_size; h->is_static = true; return 0; } int kal_buf_circ_delete(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; if (h->is_static) { // Set h to 0 memset(h->buffer, 0, h->max_length); memset(h, 0, sizeof(kal_buf_circ_static_handle_t)); } #ifdef CIRCULAR_BUFFER_DYNAMIC else { CIRCULAR_BUFFER_FREE(h->buffer); CIRCULAR_BUFFER_FREE(h); } #endif return 0; } int kal_buf_circ_reset(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; h->head = 0; h->tail = 0; memset(h->buffer, 0, h->max_length); return 0; } int kal_buf_circ_full(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // if the next head is the tail, circular buffer is full return (kal_buf_circ_next_head(h, 1) == h->tail)? true : false; } int kal_buf_circ_empty(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // if the head isn't ahead of the tail, we don't have any elements return (h->head == h->tail)? true : false; } uint32_t kal_buf_circ_size(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // head is ahead of tail if (h->head >= h->tail) { // return the difference return (h->head - h->tail) / h->element_size; } else { // else add max_length return (h->max_length + h->head - h->tail) / h->element_size; } } uint32_t kal_buf_circ_space(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; return ((h->max_length / h->element_size) - 1) - kal_buf_circ_size(handle); } int kal_buf_circ_push(kal_buf_circ_handle_t handle, uint8_t* p) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // check if circular buffer is full if (kal_buf_circ_full(handle)) { return -1; // and return with an error. } // next is where head will point to after this write. uint32_t next = kal_buf_circ_next_head(h, 1); // Load data and then move memcpy(&(h->buffer[h->head]), p, h->element_size); // head to next data offset. h->head = next; // return success to indicate successful push. return 0; } int kal_buf_circ_pop(kal_buf_circ_handle_t handle, uint8_t* p) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // check if circular buffer is empty if (kal_buf_circ_empty(handle)) { return -1; // and return with an error } // next is where tail will point to after this read. uint32_t next = kal_buf_circ_next_tail(h, 1); if (p) { // Read data and then move memcpy(p, &(h->buffer[h->tail]), h->element_size); } // tail to next data offset. h->tail = next; // return success to indicate successful pop. return 0; } int kal_buf_circ_peek(kal_buf_circ_handle_t handle, uint8_t* p) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // check if circular buffer is empty if (kal_buf_circ_empty(handle)) { return -1; // and return with an error } // Read data memcpy(p, &(h->buffer[h->tail]), h->element_size); // return success to indicate successful peek. return 0; } int kal_buf_circ_put(kal_buf_circ_handle_t handle, uint8_t* p, uint32_t nb_elements) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // Check if there is enough available spots in the buffer if (nb_elements + kal_buf_circ_size(handle) >= h->max_length / h->element_size) { return -1; // and return with an error } // check if write should be done in two parts uint32_t available_now = (h->max_length - h->head) / h->element_size; if (nb_elements > available_now) { // write first part up to max_length if (kal_buf_circ_put(handle, p, available_now)) { return -1; } // increment write pointer p += available_now * h->element_size; // subtract what we just wrote nb_elements -= available_now; } // next is where head will point to after this write. uint32_t next = kal_buf_circ_next_head(h, nb_elements); // write data memcpy(&(h->buffer[h->head]), p, nb_elements * h->element_size); // head to next data offset. h->head = next; // return success to indicate successful get. return 0; } int kal_buf_circ_get(kal_buf_circ_handle_t handle, uint8_t* p, uint32_t nb_elements) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // Check if there is enough elements in the buffer if (nb_elements > kal_buf_circ_size(handle)) { return -1; // and return with an error } // check if read should be done in two parts uint32_t available_now = (h->max_length - h->tail) / h->element_size; if (nb_elements > available_now) { // get first part up to max_length if (kal_buf_circ_get(handle, p, available_now)) { return -1; } if (p) { // increment read pointer p += available_now * h->element_size; } // subtract what we just read nb_elements -= available_now; } // next is where tail will point to after this read. uint32_t next = kal_buf_circ_next_tail(h, nb_elements); if (p) { // read data memcpy(p, &(h->buffer[h->tail]), nb_elements * h->element_size); } // tail to next data offset. h->tail = next; // return success to indicate successful get. return 0; } int kal_buf_circ_fetch(kal_buf_circ_handle_t handle, uint8_t* p, uint32_t nb_elements) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // Check if there is enough elements in the buffer if (nb_elements > kal_buf_circ_size(handle)) { return -1; // and return with an error } // check if read should be done in two parts uint32_t available_now = (h->max_length - h->tail) / h->element_size; if (nb_elements > available_now) { // get first part from tail up to max_length memcpy(p, &(h->buffer[h->tail]), available_now * h->element_size); // increment read pointer p += available_now * h->element_size; // subtract what we just read nb_elements -= available_now; // get second part from 0 up to remaining length memcpy(p, &(h->buffer[0]), nb_elements * h->element_size); } else { // get data from tail memcpy(p, &(h->buffer[h->tail]), nb_elements * h->element_size); } // return success to indicate successful fetch. return 0; } int kal_buf_circ_erase(kal_buf_circ_handle_t handle) { kal_buf_circ_static_handle_t* h = (kal_buf_circ_static_handle_t*)handle; // check if circular buffer is empty if (kal_buf_circ_empty(handle)) { return -1; // and return with an error } // head is at 0, we wrap back if (h->head == 0) { h->head = h->max_length - h->element_size; } // else go back one element else { h->head = h->head - h->element_size; } // return success to indicate successful erase. return 0; }