// 緩衝區-數組隊列實現 可在VC6.0下編譯通過
// 使用MTK平臺做DTU產品的時候,需要將串口的數據緩存到內存,然後通過網絡發送數據,
// 所以要記錄下來本次存入數據長度和數據內容,以便下次發往網絡時可將本次存入數據整段發送出去
// 另外,MTK中,動態分配內存效率較整體分配內存穩定性差,採用數組隊列形式實現
// 功能,向緩衝區讀寫數據
// 對外接口 dtu_buffer_get_data / dtu_buffer_add_data
// 本程序實現記錄本次存入數據多少,下次取出來時,會取出相同數量數據
// 最多容納數據數量份數爲MAX_L_SIZE,最多容納數據總和爲MAX_SIZE
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <time.h>
#define MAX_SIZE 1024 // 緩衝區最大容納數據總和
struct arrQueue // 聲明隊列的頭和尾節點,數據存儲元素
{
unsigned char data[MAX_SIZE+1]; // 定義數組隊列元素,能容納MAX_SIZE字節
unsigned int front; // 含有數據的第一個下標
unsigned int rear; // 含有數據的最後一個元素下標,rear所在的元素不存數據
}queue;
void initQueue()
{
memset(queue.data, '\0', sizeof(queue.data));
queue.front = 0;
queue.rear = 0;
}
void enQueue(unsigned char *pElement, unsigned int *len)//向queue中存入長度爲len字節數據,len返回長度實際存入的長度
{
// 如果rear在front前面一位,則表明緩衝區已經滿,無法存入數據
// 當rear在最後一位,front在最前一位,也是沒有空間
if ((queue.rear+1)%(MAX_SIZE+1) == queue.front)
{
*len = 0;
return;
}
// 如果rear在front前面一位以上,則rear與front之間就是空閒區域,長度爲front-rear-1
if (queue.rear+1<queue.front)
{
// 存入數據位len與剩餘空間較小者
*len = *len <= (queue.front-queue.rear-1) ? *len : queue.front-queue.rear-1;
memcpy(&queue.data[queue.rear], pElement, *len);
queue.rear += *len;
}
else // 如果 rear在front後面,或者相等時,並且有空間
{
// 剩餘空間大小爲 MAX_SIZE-(rear-front), 可寫入的數據位長度與剩餘空間較小者
*len = *len <= (MAX_SIZE-(queue.rear-queue.front)) ? *len : MAX_SIZE-(queue.rear-queue.front);
// 如果front爲0,則rear就在小於等於MAX_SIZE的位置,只需要隊列尾部保存數據
if (queue.front==0)
{
memcpy(&queue.data[queue.rear], pElement, *len);
queue.rear += *len;
}
else // 如果front不爲0,則 隊列尾保存了數據,隊列頭部有可能需要保存數據
{
// 如果尾部可以保存數據,則直接保存數據
if ((MAX_SIZE+1-queue.rear) >= *len)
{
memcpy(&queue.data[queue.rear], pElement, *len);
queue.rear = (queue.rear + *len)%(MAX_SIZE+1);
}
else // 如果尾部保存不了數據,頭部還需要保存數據,尾部保存的數據長度爲:MAX_SIZE+1-queue.rear
{
memcpy(&queue.data[queue.rear], pElement, MAX_SIZE+1-queue.rear);
queue.rear = *len-(MAX_SIZE+1-queue.rear);
memcpy(&queue.data[0], pElement+(*len-queue.rear), queue.rear);
}
}
}
}
void deQueue(unsigned char *pElement, unsigned int *len)//向queue中取出長度爲len字節數據,len返回長度實際取出的長度
{
// 如果爲空數據
if ((*len==0) || (queue.rear==queue.front))
{
*len = 0;
return;
}
// 如果 rear在front後面,則直接取出數據
if (queue.rear > queue.front)
{
*len = *len <= (queue.rear-queue.front) ? *len : (queue.rear-queue.front);
memcpy(pElement, &queue.data[queue.front], *len);
queue.front += *len;
}
else // 如果rear在front前面
{
// 隊列中數據長度爲 rear+(MAX_SIZE+1-front)
*len = *len <= queue.rear+(MAX_SIZE+1-queue.front) ? *len : queue.rear+(MAX_SIZE+1-queue.front);
// 如果尾部可以取出*len的數據則直接取,尾部數據大小爲MAX_SIZE+1-queue.front
if (*len <= MAX_SIZE+1-queue.front)
{
memcpy(pElement, &queue.data[queue.front], *len);
queue.front = (queue.front + *len) % (MAX_SIZE+1);
}
else // 如果尾部取完,還需要取數據,則取頭部數據
{
memcpy(pElement, &queue.data[queue.front], (MAX_SIZE+1-queue.front));
queue.front = *len-(MAX_SIZE+1-queue.front);
memcpy(&pElement[*len-queue.front], &queue.data[0], queue.front);
}
}
}
unsigned int lenQueue() // 隊列存了多少數據
{
return (queue.rear+MAX_SIZE+1-queue.front)%(MAX_SIZE+1);
}
/////////////////////////////////長度數組隊列///////////////////////////////////
#define MAX_L_SIZE 128 // 最多存入數據份數,一次存入數據位一份數據
struct LQueue
{
unsigned int data[MAX_L_SIZE];
unsigned int front;
unsigned int rear;
}lqueue;
void initLQueue()
{
memset(lqueue.data, '\0', sizeof(lqueue.data));
lqueue.front = 0;
lqueue.rear = 0;
}
void enLQueue(unsigned int *len) // 插入長度len, len不能爲0,插入正確len不改變,插入錯誤len爲0
{
if ((lqueue.rear+1)%MAX_L_SIZE == lqueue.front) // 隊列已滿
{
*len = 0;
}
else
{
lqueue.data[lqueue.rear] = *len;
lqueue.rear = (lqueue.rear+1)%MAX_L_SIZE;
}
}
void deLQueue(unsigned int *len) // 返回一個長度len數值,len爲0則隊列爲空
{
if (lqueue.rear == lqueue.front) // 隊列爲空
{
*len = 0;
}
else
{
*len = lqueue.data[lqueue.front];
lqueue.data[lqueue.front] = 0; // 還原數據爲0
lqueue.front = (lqueue.front+1)%MAX_L_SIZE;
}
}
unsigned int lenLQueue() // 獲取隊列存入多少len數值
{
return (lqueue.rear+MAX_L_SIZE-lqueue.front)%MAX_L_SIZE;
}
/////////////////////////////////長度隊列///////////////////////////////////
// 緩衝區對外兩個接口函數
//////////////////////////////////////////////////////////////////////
// 寫入數據到緩衝區,若緩衝區存不下需要放入的數據,則刪除前面存入的數據
unsigned char dtu_buffer_add_data(const unsigned char *pbuf, unsigned int len)
{
unsigned int len_t = 0;
unsigned char pbuf_t[128] = {0x0, };
if ((pbuf==NULL) || (len==0))
{
return 0;
}
while (MAX_SIZE-lenQueue() < len) // 如果緩衝區滿了,則刪除以前的的數據
{
deLQueue(&len_t);
deQueue((unsigned char*)pbuf_t, &len_t);
printf("【%d-%s】\r\n", len_t, pbuf_t);
}
if (MAX_L_SIZE==lenLQueue()+1) // 如果長度隊列滿了,則刪除一個長度隊列
{
deLQueue(&len_t);
deQueue((unsigned char*)pbuf_t, &len_t);
printf("【%d-%s】\r\n", len_t, pbuf_t);
}
enLQueue(&len);
enQueue((unsigned char*)pbuf, &len);
return 1;
}
// 從緩衝區獲取內容
unsigned char dtu_buffer_get_data(unsigned char* pbuf, unsigned int* len)
{
unsigned char result = 0;
if (pbuf==NULL)
return result;
deLQueue((unsigned int*)len);
deQueue((unsigned char*)pbuf, (unsigned int*)len);
if (*len)
result = 1;
return result;
}
/////////////////////////////////////////////////////////////////////////
void main()
{
int i = 0;
int len = 1;
char buf[32];
initQueue();
// 測試1,正常情況
queue.front = 0;
queue.rear = 0;
// 測試2,front在前,rear在後
//queue.front = 5;
//queue.rear = 7;
// 測試3,front在後,rear在前
//queue.front = 26;
//queue.rear = 8;
// 測試四個存入////////////////////////
printf("begin==========\r\n");
for (i=0, len=1; len; i++)
{
len = 4;
buf[0] = 'A'+4*i;
buf[1] = 'A'+4*i+1;
buf[2] = 'A'+4*i+2;
buf[3] = 'A'+4*i+3;
printf("%d-", lenQueue());
enQueue(buf, &len);
printf("%d ", len);
}
printf("\r\n");
for (i=0; i<MAX_SIZE+1; i++)
{
printf("%c ", queue.data[i]);
}
printf("\r\n");
// 測試四個存入 end////////////////////
// 測試四個取出////////////////////////
for (i=0, len=1; len; i++)
{
len = 4;
printf("%d-", lenQueue());
deQueue(buf, &len);
buf[len] = '\0';
printf("%d-%s\r\n", len, buf);
}
printf("end============\r\n");
// 測試四個取出 end////////////////////
// 採用隨機數測試//////////////////////
{
int value_f;
int value_r;
srand(time(0));
value_f = rand() % (MAX_SIZE+1);
value_r = rand() % (MAX_SIZE+1);
initQueue();
queue.front = value_f;
queue.rear = value_r;
printf("\r\nbegin========== %d %d\r\n", value_f, value_r);
for (i=0, len=1; len; i++)
{
len = 4;
buf[0] = 'A'+4*i;
buf[1] = 'A'+4*i+1;
buf[2] = 'A'+4*i+2;
buf[3] = 'A'+4*i+3;
printf("%d-", lenQueue());
enQueue(buf, &len);
printf("%d ", len);
}
printf("\r\n");
for (i=0; i<MAX_SIZE+1; i++)
{
printf("%c ", queue.data[i]);
}
printf("\r\n");
for (i=0, len=1; len; i++)
{
len = 4;
printf("%d-", lenQueue());
deQueue(buf, &len);
buf[len] = '\0';
printf("%d-%s\r\n", len, buf);
}
printf("\r\nend============\r\n");
}
// 採用隨機數測試 end//////////////////
////////////////////////////測試lqueue////////////////////////
initLQueue();
lqueue.front = 0;
lqueue.rear = 0;
// 測試存入////////////////////////
printf("\r\nlqueue begin==========\r\n");
for (i=0, len=i+1; len; i++)
{
len = i+1;
enLQueue(&len);
printf("%d-%d ", lenLQueue(), len);
if (!((i+1)%3)) // 測試取出一部分數據
{
deLQueue(&len);
printf("de-%d ", len);
}
}
printf("\r\n");
for (i=0; i<MAX_L_SIZE; i++)
{
printf("%d ", lqueue.data[i]);
}
printf("\r\n");
// 測試取出/////////////////////////////
for (len = 1; len; )
{
printf("%d-", lenLQueue());
deLQueue(&len);
printf("%d ", len);
}
printf("\r\n");
for (i=0; i<MAX_L_SIZE; i++)
{
printf("%d ", lqueue.data[i]);
}
printf("\r\nlqueue end============\r\n");
// 測試end////////////////////
////////////////////////////測試lqueue////////////////////////
// 測試 dtu_buffer_add_data / dtu_buffer_get_data
////////////////////////////測試 begin////////////////////////
printf("add begin============\r\n");
len = 4;
i = 0;
while (i!=10)
{
sprintf(buf, "abc%d", i);
dtu_buffer_add_data(buf, len);
i++;
}
printf("add end=============\r\n");
printf("get begin============\r\n");
while (dtu_buffer_get_data(buf, &len) )
{
printf("%d-%s\r\n", len, buf);
}
printf("get end=============\r\n");
// 測試end////////////////////
////////////////////////////測試 end//////////////////////////
}