/* * Copyright (C) 2004 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. Neither the name of the copyright holders nor the names of * contributors may 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 OWNER 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. * * For additional information see http://www.ethernut.de/ * */ /*! * $Log$ * Revision 1.7 2009/02/06 15:40:29 haraldkipp * Using newly available strdup() and calloc(). * Replaced NutHeap routines by standard malloc/free. * Replaced pointer value 0 by NULL. * * Revision 1.6 2008/08/11 07:00:33 haraldkipp * BSD types replaced by stdint types (feature request #1282721). * * Revision 1.5 2008/02/15 17:08:05 haraldkipp * Calling the initialization routine more than once is now possible. * By default, half of the available memory will be allocated. Previous * versions eat all free memory but 8k. * * Revision 1.4 2007/04/12 09:08:57 haraldkipp * Segmented buffer routines ported to ARM. * * Revision 1.3 2004/12/17 15:28:33 haraldkipp * Bugfix. Comparison of the read and write pointers now includes the segments. * Thanks to Pete Allinson and Johan van der Stoel. * * Revision 1.2 2004/08/18 18:51:56 haraldkipp * Made banked memory configurable. * * Revision 1.1 2003/07/21 18:19:48 haraldkipp * First check in * */ #include #include /*! * \addtogroup xgBankMem */ /*@{*/ #include static char segbuf_empty; static uint32_t segbuf_total; static uint32_t segbuf_used; static char *segbuf_start; static char *segbuf_end; static char *segbuf_wp; static char segbuf_ws; static char *segbuf_rp; static char segbuf_rs; /*! * \brief Reset the segmented buffer. * * \return Pointer to the first buffer segment. */ char *NutSegBufReset(void) { segbuf_rp = segbuf_wp = segbuf_start; segbuf_rs = segbuf_ws = 0; NutSegBufEnable(0); segbuf_empty = 1; segbuf_used = 0; return segbuf_start; } /*! * \brief Initialize the segmented buffer. * * \param size Number of bytes to allocate for the global buffer. * In systems with banked memory this parameter is * ignored and all banked memory is occupied for the * global buffer. In systems without banked memory, * the specified number of bytes is taken from heap * memory. * * \return Pointer to the first buffer segment or null on failures. */ char *NutSegBufInit(size_t size) { #if NUTBANK_COUNT segbuf_start = (char *)(NUTBANK_START); segbuf_end = (char *)(NUTBANK_START) + NUTBANK_SIZE; segbuf_total = (uint32_t) NUTBANK_COUNT *(uint32_t) NUTBANK_SIZE; #else if (size == 0) size = NutHeapAvailable() / 2; if (segbuf_start) { NutHeapFree(segbuf_start); } if ((segbuf_start = NutHeapAlloc(size)) != NULL) segbuf_end = segbuf_start + size; segbuf_total = size; #endif return NutSegBufReset(); } /*! * \brief Request segmented buffer space for writing. * * This call will also enable the current write segment and * may disable the current read segment. * * \param bcp Pointer to a variable, which receives the * number of consecutive bytes available for * writing. * * \return Pointer to the next write position. */ char *NutSegBufWriteRequest(size_t * bcp) { if (segbuf_empty || segbuf_ws != segbuf_rs || segbuf_wp > segbuf_rp) *bcp = segbuf_end - segbuf_wp; else *bcp = segbuf_rp - segbuf_wp; NutSegBufEnable(segbuf_ws); return segbuf_wp; } /*! * \brief Request segmented buffer space for reading. * * This call will also enable the current read segment and * may disable the current write segment. * * \param bcp Pointer to a variable, which receives the * number of consecutive bytes available for * reading. * * \return Pointer to the next read position. */ char *NutSegBufReadRequest(size_t * bcp) { if (segbuf_empty) *bcp = 0; else if (segbuf_ws != segbuf_rs || segbuf_rp >= segbuf_wp) *bcp = segbuf_end - segbuf_rp; else if ((*bcp = segbuf_wp - segbuf_rp) == 0 && segbuf_ws == segbuf_rs) segbuf_empty = 1; NutSegBufEnable(segbuf_rs); return segbuf_rp; } /*! * \brief Commit written buffer space. * * The write pointer will be incremented by the specified number of bytes. * If the pointer reaches the end of a segment, the next segment will be * enabled and the pointer will point to the start of the new segement. * * \param bc Number of bytes to commit. * * \return Pointer to the next write position. */ char *NutSegBufWriteCommit(size_t bc) { if (bc) { segbuf_wp += bc; segbuf_empty = 0; segbuf_used += bc; if (segbuf_wp == segbuf_end) { segbuf_wp = segbuf_start; #if NUTBANK_COUNT > 0 if (++segbuf_ws >= NUTBANK_COUNT) segbuf_ws = 0; #endif NutSegBufEnable(segbuf_ws); } } return segbuf_wp; } /*! * \brief Commit read buffer space. * * The read pointer will be incremented by the specified number of bytes. * If the pointer reaches the end of a segment, the next segment will be * enabled and the pointer will point to the start of the new segement. * * \param bc Number of bytes to commit. * * \return Pointer to the next read position. */ char *NutSegBufReadCommit(size_t bc) { if (bc) { segbuf_rp += bc; segbuf_used -= bc; if (segbuf_rp == segbuf_end) { segbuf_rp = segbuf_start; #if NUTBANK_COUNT > 0 if (++segbuf_rs >= NUTBANK_COUNT) segbuf_rs = 0; #endif NutSegBufEnable(segbuf_rs); } if (segbuf_rp == segbuf_wp && segbuf_rs == segbuf_ws) segbuf_empty = 1; } return segbuf_rp; } /*! * \brief Commit written buffer space and finish write access. * * The write pointer will be incremented by the specified number of bytes. * This call will also enable the current read segment and may disable the * current write segment. * * \param bc Number of bytes to commit. */ void NutSegBufWriteLast(size_t bc) { if (bc) { segbuf_wp += bc; segbuf_used += bc; segbuf_empty = 0; if (segbuf_wp == segbuf_end) { segbuf_wp = segbuf_start; #if NUTBANK_COUNT > 0 if (++segbuf_ws >= NUTBANK_COUNT) segbuf_ws = 0; #endif } } NutSegBufEnable(segbuf_rs); } /*! * \brief Commit written buffer space and finish read access. * * The write pointer will be incremented by the specified number of bytes. * This call will also enable the current read segment and may disable the * current write segment. * * \param bc Number of bytes to commit. */ void NutSegBufReadLast(size_t bc) { if (bc) { segbuf_rp += bc; segbuf_used -= bc; if (segbuf_rp == segbuf_end) { segbuf_rp = segbuf_start; #if NUTBANK_COUNT > 0 if (++segbuf_rs >= NUTBANK_COUNT) segbuf_rs = 0; #endif } if (segbuf_rp == segbuf_wp && segbuf_rs == segbuf_ws) segbuf_empty = 1; } NutSegBufEnable(segbuf_ws); } /*! * \brief Return the available buffer space. * * \return Total number of free bytes in the buffer. */ uint32_t NutSegBufAvailable(void) { return segbuf_total - segbuf_used; } /*! * \brief Return the used buffer space. * * \return Total number of used bytes in the buffer. */ uint32_t NutSegBufUsed(void) { return segbuf_used; } /*@}*/