--- /dev/null
+/*******************************************************************
+ uLan Utilities Library - C library of basic reusable constructions
+
+ ul_cbuff.h - circular buffer
+
+ (C) Copyright 2006 by Pavel Pisa - Originator
+
+ The uLan utilities library can be used, copied and modified under
+ next licenses
+ - GPL - GNU General Public License
+ - LGPL - GNU Lesser General Public License
+ - MPL - Mozilla Public License
+ - and other licenses added by project originators
+ Code can be modified and re-distributed under any combination
+ of the above listed licenses. If contributor does not agree with
+ some of the licenses, he/she can delete appropriate line.
+ Warning, if you delete all lines, you are not allowed to
+ distribute source code and/or binaries utilizing code.
+
+ See files COPYING and README for details.
+
+ *******************************************************************/
+
+#ifndef _UL_CBUFF_H
+#define _UL_CBUFF_H
+
+#include "ul_utdefs.h"
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UL_CBUFF_NO_INLINE
+
+#ifndef UL_CBUFF_NO_INLINE
+#define UL_CBUFF_INLINE
+#endif
+
+#ifndef ul_cbuff_inline
+#ifdef UL_CBUFF_INLINE
+#define ul_cbuff_inline static inline
+#else
+#define ul_cbuff_inline
+#endif
+#endif
+
+#define ul_cbuff_align(x) (((x)+3)&~3)
+
+typedef unsigned int ul_cbuff_loc_t;
+
+typedef struct ul_cbuff_msg_head_t {
+ unsigned short flags;
+ unsigned short length;
+} ul_cbuff_msg_head_t;
+
+#define UL_CBUFF_MSG_READY 0x8000
+#define UL_CBUFF_MSG_OVERFLOW 0x4000
+#define UL_CBUFF_MSG_READERS 0x3fff
+
+#define ul_cbuff_msg_head_size (ul_cbuff_align(sizeof(ul_cbuff_msg_head_t)))
+
+typedef struct ul_cbuff_state_t {
+ ul_cbuff_loc_t buff_size;
+ ul_cbuff_loc_t head;
+ ul_cbuff_loc_t lasttail;
+ ul_cbuff_loc_t firsttail;
+ unsigned int cycles;
+ unsigned int readers;
+ ul_cbuff_loc_t rear_size;
+} ul_cbuff_state_t;
+
+typedef struct ul_cbuff_t {
+ unsigned char *buff_start;
+ ul_cbuff_state_t *state;
+} ul_cbuff_t;
+
+typedef struct ul_cbuff_data_info_t {
+ unsigned char *ptr;
+ unsigned char *wrap_ptr;
+ unsigned int cont_len;
+ unsigned int wrap_len;
+} ul_cbuff_data_info_t;
+
+typedef struct ul_cbuff_put_info_t {
+ ul_cbuff_data_info_t data;
+ ul_cbuff_msg_head_t *msg_head;
+} ul_cbuff_put_info_t;
+
+typedef struct ul_cbuff_tail_info_t {
+ ul_cbuff_data_info_t data;
+ ul_cbuff_msg_head_t *msg_head;
+} ul_cbuff_tail_info_t;
+
+#if !defined(UL_CBUFF_INLINE)
+
+void ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg);
+int ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg);
+int ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags);
+int ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info);
+ul_cbuff_loc_t ul_cbuff_head_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
+ul_cbuff_loc_t ul_cbuff_next_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
+int ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode);
+int ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info);
+int ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next);
+void ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info);
+int ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size);
+int ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size);
+int ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size);
+void *ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head);
+void *ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc);
+
+#endif /* UL_CBUFF_INLINE */
+
+#if defined(UL_CBUFF_INLINE) || defined(UL_CBUFF_INCLUDE_INTERNAL)
+
+ul_cbuff_inline void
+ul_cbuff_mark_ready(ul_cbuff_msg_head_t *msg)
+{
+ msg->flags|=UL_CBUFF_MSG_READY;
+}
+
+ul_cbuff_inline int
+ul_cbuff_is_ready(const ul_cbuff_msg_head_t *msg)
+{
+ return msg->flags&UL_CBUFF_MSG_READY;
+}
+
+ul_cbuff_inline int
+ul_cbuff_head_alloc(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info, unsigned int size, unsigned int flags)
+{
+ ul_cbuff_state_t *state=buff->state;
+ unsigned int length=size;
+
+ size=ul_cbuff_align(size+state->rear_size)+ul_cbuff_msg_head_size;
+
+ if((state->lasttail > state->head) &&
+ (state->lasttail-state->head <= size))
+ return -1;
+
+ if((state->lasttail > state->head) ||
+ (state->buff_size-state->head > size)){
+ put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
+
+ put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
+ put_info->data.cont_len=length;
+ put_info->data.wrap_ptr=NULL;
+ put_info->data.wrap_len=0;
+
+ state->head+=size;
+ }else{
+ ul_cbuff_loc_t res_size=state->buff_size-state->head;
+ if(size-res_size >= state->lasttail)
+ return -1;
+
+ put_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
+
+ if(res_size != ul_cbuff_msg_head_size){
+ put_info->data.ptr=(buff->buff_start+state->head+ul_cbuff_msg_head_size);
+ put_info->data.cont_len=res_size-ul_cbuff_msg_head_size;
+ if(put_info->data.cont_len<length){
+ put_info->data.wrap_ptr=buff->buff_start;
+ put_info->data.wrap_len=length-put_info->data.cont_len;
+ }else{
+ put_info->data.wrap_ptr=NULL;
+ put_info->data.wrap_len=0;
+ }
+ }else{
+ put_info->data.ptr=buff->buff_start;
+ put_info->data.cont_len=length;
+ put_info->data.wrap_ptr=NULL;
+ put_info->data.wrap_len=0;
+ }
+
+ state->cycles++;
+ state->head=size-res_size;
+ }
+
+ ((ul_cbuff_msg_head_t *)(buff->buff_start+state->head))->flags=0;
+
+ put_info->msg_head->flags|=flags;
+ put_info->msg_head->length=length;
+
+ return 0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_head_put(ul_cbuff_t *buff, ul_cbuff_put_info_t *put_info)
+{
+ if(buff->state->readers>0)
+ put_info->msg_head->flags+=buff->state->readers;
+ ul_cbuff_mark_ready(put_info->msg_head);
+ put_info->msg_head=NULL;
+ return 0;
+}
+
+ul_cbuff_inline ul_cbuff_loc_t
+ul_cbuff_head_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
+{
+ return (unsigned char*)msg_head-buff->buff_start;
+}
+
+ul_cbuff_inline ul_cbuff_loc_t
+ul_cbuff_next_loc(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
+{
+ ul_cbuff_loc_t loc;
+ unsigned int size;
+
+ size=ul_cbuff_align(msg_head->length+buff->state->rear_size)+ul_cbuff_msg_head_size;
+
+ loc=(unsigned char*)msg_head-buff->buff_start;
+ if(buff->state->buff_size-loc > size)
+ loc+=size;
+ else
+ loc=size-(buff->state->buff_size-loc);
+
+ return loc;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_attach(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info, int mode)
+{
+ ul_cbuff_state_t *state=buff->state;
+ ul_cbuff_msg_head_t *msg_head;
+
+ msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+state->head);
+ if(state->readers>=0)
+ state->readers++;
+ if((state->readers<0)||(state->firsttail==state->head)){
+ tail_info->msg_head=msg_head;
+ tail_info->data.ptr=NULL;
+ }else{
+ /* There is already some message(s) write in progress */
+ tail_info->msg_head=NULL;
+ tail_info->msg_head->flags++;
+ /* Some data fields are abused for ready condition checking */
+ tail_info->data.ptr=(unsigned char*)msg_head;
+ tail_info->data.wrap_ptr=buff->buff_start+state->firsttail;
+ tail_info->data.wrap_len=state->cycles;
+ }
+ return 0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_incontact(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+ if(tail_info->msg_head==NULL){
+ unsigned char *new_firsttail=buff->buff_start+buff->state->firsttail;
+ unsigned char *old_head=tail_info->data.ptr;
+ unsigned char *old_firsttail=tail_info->data.wrap_ptr;
+ unsigned int old_cycles=tail_info->data.wrap_len;
+ unsigned int new_cycles=buff->state->cycles;
+
+ if(old_firsttail<old_head){
+ if((new_firsttail<old_head)&&(new_cycles==old_cycles))
+ return 0;
+ }else{
+ if(new_cycles==old_cycles)
+ return 0;
+ if((new_firsttail<old_head)&&((new_cycles-old_cycles)==1))
+ return 0;
+ }
+ tail_info->msg_head=(ul_cbuff_msg_head_t *)old_head;
+ return 1;
+ }
+ return 1;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_test(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+ ul_cbuff_loc_t res_size;
+ unsigned int length;
+ ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
+
+ if(!msg_head)
+ return -1;
+
+ if(!ul_cbuff_is_ready(msg_head))
+ return 0;
+
+ res_size=buff->state->buff_size-((unsigned char*)msg_head-buff->buff_start);
+ length=msg_head->length;
+
+ if(res_size > ul_cbuff_msg_head_size){
+ tail_info->data.ptr=(unsigned char*)msg_head+ul_cbuff_msg_head_size;
+ if(res_size-ul_cbuff_msg_head_size >= length){
+ tail_info->data.cont_len=length;
+ tail_info->data.wrap_ptr=NULL;
+ tail_info->data.wrap_len=0;
+ }else{
+ tail_info->data.cont_len=res_size-ul_cbuff_msg_head_size;
+ tail_info->data.wrap_ptr=buff->buff_start;
+ tail_info->data.wrap_len=length-(res_size-ul_cbuff_msg_head_size);
+ }
+ } else {
+ tail_info->data.ptr=buff->buff_start;
+ tail_info->data.cont_len=length;
+ tail_info->data.wrap_ptr=NULL;
+ tail_info->data.wrap_len=0;
+ }
+ return msg_head->flags;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_release(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+ ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
+ unsigned msg_readers;
+
+ if(!ul_cbuff_is_ready(msg_head))
+ return -1;
+
+ if(buff->state->readers<=0)
+ return 1;
+
+ msg_readers=msg_head->flags&UL_CBUFF_MSG_READERS;
+ if(msg_readers)
+ msg_head->flags--;
+
+ return msg_readers<=1?1:0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_next(ul_cbuff_t *buff, ul_cbuff_tail_info_t *tail_info)
+{
+ ul_cbuff_msg_head_t *msg_head=tail_info->msg_head;
+
+ if(!ul_cbuff_is_ready(msg_head))
+ return -1;
+
+ tail_info->msg_head=(ul_cbuff_msg_head_t *)(buff->buff_start+
+ ul_cbuff_next_loc(buff, msg_head));
+ return 0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_tail_state_update(ul_cbuff_t *buff, int release_result, ul_cbuff_loc_t loc, ul_cbuff_loc_t loc_next)
+{
+ if(loc==buff->state->firsttail)
+ buff->state->firsttail=loc_next;
+
+ if(release_result<=0)
+ return 0;
+
+ if(loc==buff->state->lasttail){
+ buff->state->lasttail=loc_next;
+ return 1;
+ }else{
+ return -1;
+ }
+}
+
+ul_cbuff_inline void
+ul_cbuff_data_do_wrap(ul_cbuff_data_info_t *data_info)
+{
+ data_info->ptr=data_info->wrap_ptr;
+ data_info->cont_len=data_info->wrap_len;
+ data_info->wrap_ptr=NULL;
+ data_info->wrap_len=0;
+}
+
+ul_cbuff_inline int
+ul_cbuff_data_at_once(ul_cbuff_data_info_t *data_info, void **pptr, int size)
+{
+ int cont_len;
+
+ *pptr=data_info->ptr;
+ if(!data_info->ptr)
+ return 0;
+ cont_len=data_info->cont_len;
+ if(cont_len>size){
+ cont_len=size;
+ data_info->ptr+=size;
+ data_info->cont_len-=cont_len;
+ }else{
+ ul_cbuff_data_do_wrap(data_info);
+ }
+ return cont_len;
+}
+
+ul_cbuff_inline int
+ul_cbuff_put_data(ul_cbuff_data_info_t *data_info, const void *data, int size)
+{
+ void *ptr;
+ int count;
+ int cont_len;
+
+ ptr=data_info->ptr;
+ if(!ptr)
+ return 0;
+ cont_len=data_info->cont_len;
+ if(cont_len>size){
+ cont_len=size;
+ data_info->ptr+=size;
+ data_info->cont_len-=cont_len;
+ }else{
+ ul_cbuff_data_do_wrap(data_info);
+ }
+ if(cont_len<=0)
+ return 0;
+ memcpy(ptr,data,cont_len);
+ count=cont_len;
+ cont_len=size-cont_len;
+ if(!cont_len)
+ return count;
+
+ ptr=data_info->ptr;
+ if(!ptr)
+ return count;
+ data=(char*)data+count;
+ if(cont_len>data_info->cont_len)
+ cont_len=data_info->cont_len;
+ data_info->ptr+=cont_len;
+ data_info->cont_len-=cont_len;
+ memcpy(ptr,data,cont_len);
+
+ return cont_len+count;
+}
+
+ul_cbuff_inline int
+ul_cbuff_get_data(ul_cbuff_data_info_t *data_info, void *data, int size)
+{
+ void *ptr;
+ int count;
+ int cont_len;
+
+ ptr=data_info->ptr;
+ if(!ptr)
+ return 0;
+ cont_len=data_info->cont_len;
+ if(cont_len>size){
+ cont_len=size;
+ data_info->ptr+=size;
+ data_info->cont_len-=cont_len;
+ }else{
+ ul_cbuff_data_do_wrap(data_info);
+ }
+ if(cont_len<=0)
+ return 0;
+ memcpy(data,ptr,cont_len);
+ count=cont_len;
+ cont_len=size-cont_len;
+ if(!cont_len)
+ return count;
+
+ ptr=data_info->ptr;
+ if(!ptr)
+ return count;
+ data=(char*)data+count;
+ if(cont_len>data_info->cont_len)
+ cont_len=data_info->cont_len;
+ data_info->ptr+=cont_len;
+ data_info->cont_len-=cont_len;
+ memcpy(data,ptr,cont_len);
+
+ return cont_len+count;
+}
+
+
+ul_cbuff_inline void *
+ul_cbuff_get_rear_ptr(ul_cbuff_t *buff, ul_cbuff_msg_head_t *msg_head)
+{
+ ul_cbuff_loc_t loc;
+ unsigned int size;
+ ul_cbuff_state_t *state=buff->state;
+
+ size=ul_cbuff_align(msg_head->length+state->rear_size)+ul_cbuff_msg_head_size;
+ size-=state->rear_size;
+
+ loc=(unsigned char*)msg_head-buff->buff_start;
+ if(state->buff_size-loc > size)
+ loc+=size;
+ else
+ loc=size-(state->buff_size-loc);
+
+ return buff->buff_start+loc;
+}
+
+ul_cbuff_inline void *
+ul_cbuff_prev_rear_ptr(ul_cbuff_t *buff, ul_cbuff_loc_t loc)
+{
+ ul_cbuff_state_t *state=buff->state;
+
+ if(loc>state->rear_size)
+ return buff->buff_start+loc-state->rear_size;
+ else
+ return buff->buff_start+loc+state->buff_size-state->rear_size;
+}
+
+#endif /*UL_CBUFF_INLINE*/
+
+int ul_cbuff_init(ul_cbuff_t *buff, ul_cbuff_state_t *state,
+ void *buff_start, ul_cbuff_loc_t size);
+
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* _UL_CBUFF_H */