pinebuds/utils/cqueue/cqueue.c

383 lines
7.8 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
/***
* cqueue.c - c circle queue c file
*/
#include "cqueue.h"
#include "cmsis.h"
#include "hal_uart.h"
#include <stdio.h>
#include <string.h>
//#define DEBUG_CQUEUE 1
CQ_FUNC_ATTR
int InitCQueue(CQueue *Q, unsigned int size, CQItemType *buf) {
Q->size = size;
Q->base = buf;
Q->len = 0;
if (!Q->base)
return CQ_ERR;
Q->read = Q->write = 0;
return CQ_OK;
}
CQ_FUNC_ATTR
int IsEmptyCQueue(CQueue *Q) {
if (Q->len == 0)
return CQ_OK;
else
return CQ_ERR;
}
CQ_FUNC_ATTR
int LengthOfCQueue(CQueue *Q) { return Q->len; }
CQ_FUNC_ATTR
int AvailableOfCQueue(CQueue *Q) { return (Q->size - Q->len); }
#if 1
CQ_FUNC_ATTR
int EnCQueue(CQueue *Q, CQItemType *e, unsigned int len) {
if (AvailableOfCQueue(Q) < len) {
return CQ_ERR;
}
Q->len += len;
uint32_t bytesToTheEnd = Q->size - Q->write;
if (bytesToTheEnd > len) {
memcpy((uint8_t *)&Q->base[Q->write], (uint8_t *)e, len);
Q->write += len;
} else {
memcpy((uint8_t *)&Q->base[Q->write], (uint8_t *)e, bytesToTheEnd);
memcpy((uint8_t *)&Q->base[0], (((uint8_t *)e) + bytesToTheEnd),
len - bytesToTheEnd);
Q->write = len - bytesToTheEnd;
}
return CQ_OK;
}
int EnCQueue_AI(CQueue *Q, CQItemType *e, unsigned int len) {
uint32_t bytesToTheEnd = Q->size - Q->write;
uint32_t readBytesToTheEnd = Q->size - Q->read;
if (AvailableOfCQueue(Q) < len) {
if (readBytesToTheEnd > len) {
Q->read += len;
} else {
Q->read = len - readBytesToTheEnd;
}
} else {
Q->len += len;
}
if (bytesToTheEnd > len) {
memcpy((uint8_t *)&Q->base[Q->write], (uint8_t *)e, len);
Q->write += len;
} else {
memcpy((uint8_t *)&Q->base[Q->write], (uint8_t *)e, bytesToTheEnd);
memcpy((uint8_t *)&Q->base[0], (((uint8_t *)e) + bytesToTheEnd),
len - bytesToTheEnd);
Q->write = len - bytesToTheEnd;
}
return CQ_OK;
}
#else
static inline void memcpy_u8(void *dst, void *src, unsigned int len) {
unsigned int i = 0;
unsigned int *d8, *s8;
d8 = dst;
s8 = src;
for (i = 0; i < len; i++)
d8[i] = s8[i];
}
static inline void memcpy_u32(void *dst, void *src, unsigned int len) {
unsigned int i = 0;
unsigned int *d32, *s32;
d32 = dst;
s32 = src;
for (i = 0; i < len; i++)
d32[i] = s32[i];
}
CQ_FUNC_ATTR
int EnCQueue(CQueue *Q, CQItemType *e, unsigned int len) {
unsigned char *src = e;
unsigned char *dst = &(Q->base[Q->write]);
unsigned int cnt_u8;
unsigned int cnt_u32;
unsigned int cnt_u32_res;
unsigned int front_u8;
unsigned int front_u32;
unsigned int front_u32_res;
unsigned int end_u8;
unsigned int end_u32;
unsigned int end_u32_res;
bool unaligned_en;
if (AvailableOfCQueue(Q) < len) {
return CQ_ERR;
}
Q->len += len;
end_u8 = Q->size - Q->write;
end_u32 = end_u8 / 4;
end_u32_res = end_u8 % 4;
cnt_u8 = len;
cnt_u32 = cnt_u8 / 4;
cnt_u32_res = cnt_u8 % 4;
unaligned_en = config_unaligned_access(true);
if (cnt_u8 <= end_u8) {
memcpy_u32(dst, src, cnt_u32);
if (cnt_u32_res) {
src += cnt_u32 * 4;
dst += cnt_u32 * 4;
memcpy_u8(dst, src, cnt_u32_res);
}
// Deal with Q->write
Q->write += cnt_u8;
} else {
front_u8 = len - end_u8;
front_u32 = front_u8 / 4;
front_u32_res = front_u8 % 4;
// Deal with end data
memcpy_u32(dst, src, end_u32);
src += end_u32 * 4;
dst += end_u32 * 4;
memcpy_u8(dst, src, end_u32_res);
src += end_u32_res;
dst = &(Q->base[0]);
// Deal with front data
memcpy_u32(dst, src, front_u32);
if (front_u32_res) {
src += front_u32 * 4;
dst += front_u32 * 4;
memcpy_u8(dst, src, front_u32_res);
}
// Deal with Q->write
Q->write = front_u8;
}
config_unaligned_access(unaligned_en);
return CQ_OK;
}
void memcpy_fast(char *dst, char *src, unsigned int len) {
int size = len / 4;
int mod = len % 4;
int *Dst = (int *)dst;
int *Src = (int *)src;
int dst_offset = (int)Dst - (int)dst;
int src_offset = (int)Src - (int)src;
if (!dst_offset && !src_offset) {
memcpy_u32(Dst, Src, size);
if (mod) {
memcpy_u8(Dst + size, Src + size, mod);
}
} else {
memcpy_u8(dst, src, len);
}
}
#endif
CQ_FUNC_ATTR
int EnCQueueFront(CQueue *Q, CQItemType *e, unsigned int len) {
if (AvailableOfCQueue(Q) < len) {
return CQ_ERR;
}
Q->len += len;
/* walk to last item , revert write */
e = e + len - 1;
if (Q->read == 0)
Q->read = Q->size - 1;
else
Q->read--;
while (len > 0) {
Q->base[Q->read] = *e;
--Q->read;
--e;
--len;
if (Q->read < 0)
Q->read = Q->size - 1;
}
/* we walk one more, walk back */
if (Q->read == Q->size - 1)
Q->read = 0;
else
++Q->read;
return CQ_OK;
}
CQ_FUNC_ATTR
int DeCQueue(CQueue *Q, CQItemType *e, unsigned int len) {
if (LengthOfCQueue(Q) < len)
return CQ_ERR;
Q->len -= len;
if (e != NULL) {
uint32_t bytesToTheEnd = Q->size - Q->read;
if (bytesToTheEnd > len) {
memcpy((uint8_t *)e, (uint8_t *)&Q->base[Q->read], len);
Q->read += len;
} else {
memcpy((uint8_t *)e, (uint8_t *)&Q->base[Q->read], bytesToTheEnd);
memcpy((((uint8_t *)e) + bytesToTheEnd), (uint8_t *)&Q->base[0],
len - bytesToTheEnd);
Q->read = len - bytesToTheEnd;
}
} else {
if (0 < Q->size) {
Q->read = (Q->read + len) % Q->size;
} else {
Q->read = 0;
}
}
return CQ_OK;
}
CQ_FUNC_ATTR
int PeekCQueue(CQueue *Q, unsigned int len_want, CQItemType **e1,
unsigned int *len1, CQItemType **e2, unsigned int *len2) {
if (LengthOfCQueue(Q) < len_want) {
return CQ_ERR;
}
*e1 = &(Q->base[Q->read]);
if ((Q->write > Q->read) || (Q->size - Q->read >= len_want)) {
*len1 = len_want;
*e2 = NULL;
*len2 = 0;
return CQ_OK;
} else {
*len1 = Q->size - Q->read;
*e2 = &(Q->base[0]);
*len2 = len_want - *len1;
return CQ_OK;
}
return CQ_ERR;
}
int PeekCQueueToBuf(CQueue *Q, CQItemType *e, unsigned int len) {
int status = CQ_OK;
unsigned char *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
status = PeekCQueue(Q, len, &e1, &len1, &e2, &len2);
if (status == CQ_OK) {
if (len == (len1 + len2)) {
memcpy(e, e1, len1);
memcpy(e + len1, e2, len2);
} else {
status = CQ_ERR;
}
}
return status;
}
int PullCQueue(CQueue *Q, CQItemType *e, unsigned int len) {
int status = CQ_OK;
unsigned char *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
status = PeekCQueue(Q, len, &e1, &len1, &e2, &len2);
if (status == CQ_OK) {
if (len == (len1 + len2)) {
memcpy(e, e1, len1);
memcpy(e + len1, e2, len2);
DeCQueue(Q, 0, len);
} else {
status = CQ_ERR;
}
}
return status;
}
#ifdef DEBUG_CQUEUE
int DumpCQueue(CQueue *Q) {
CQItemType e;
int len = 0, i = 0;
len = LengthOfCQueue(Q);
if (len <= 0)
return CQ_ERR;
i = Q->read;
while (len > 0) {
e = Q->base[i];
TRACE(stderr, "-0x%x", e);
TRACE(stderr, "-%c", e);
++i;
--len;
if (i == Q->size)
i = 0;
}
return CQ_ERR;
}
#endif
void ResetCQueue(CQueue *Q) {
Q->len = 0;
Q->read = Q->write = 0;
}