[DeviceDriver] Add rbb (ring block buffer) data structure.

This commit is contained in:
armink 2018-09-11 19:56:38 +08:00
parent 7d3f38e4f6
commit dff8a2c513
4 changed files with 991 additions and 0 deletions

View File

@ -0,0 +1,115 @@
/*
* File : ringblk_buf.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-08-25 armink the first version
*/
#ifndef _RINGBLK_BUF_H_
#define _RINGBLK_BUF_H_
/*
* Introduction:
* The rbb is the ring buffer which is composed with many blocks. It is different from the ring buffer.
* The ring buffer is only composed with chars. The rbb put and get supported zero copies. So the rbb
* is very suitable for put block and get block by a certain order. Such as DMA block transmit,
* communicate frame send/recv, and so on.
*/
#ifdef __cplusplus
extern "C" {
#endif
enum rt_rbb_status
{
/* unused status when first initialize or after blk_free() */
RT_RBB_BLK_UNUSED,
/* initialized status after blk_alloc() */
RT_RBB_BLK_INITED,
/* put status after blk_put() */
RT_RBB_BLK_PUT,
/* get status after blk_get() */
RT_RBB_BLK_GET,
};
typedef enum rt_rbb_status rt_rbb_status_t;
/**
* the block of rbb
*/
struct rt_rbb_blk
{
rt_rbb_status_t status :8;
/* less then 2^24 */
rt_size_t size :24;
rt_uint8_t *buf;
rt_slist_t list;
};
typedef struct rt_rbb_blk *rt_rbb_blk_t;
/**
* Rbb block queue: the blocks (from block1->buf to blockn->buf) memory which on this queue is continuous.
*/
struct rt_rbb_blk_queue
{
rt_rbb_blk_t blocks;
rt_size_t blk_num;
};
typedef struct rt_rbb_blk_queue *rt_rbb_blk_queue_t;
/**
* ring block buffer
*/
struct rt_rbb
{
rt_uint8_t *buf;
rt_size_t buf_size;
/* all of blocks */
rt_rbb_blk_t blk_set;
rt_size_t blk_max_num;
/* saved the initialized and put status blocks */
rt_slist_t blk_list;
};
typedef struct rt_rbb *rt_rbb_t;
/* rbb (ring block buffer) API */
void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num);
rt_rbb_t rt_rbb_create(rt_size_t buf_size, rt_size_t blk_max_num);
void rt_rbb_destroy(rt_rbb_t rbb);
rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb);
/* rbb block API */
rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size);
void rt_rbb_blk_put(rt_rbb_blk_t block);
rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb);
void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block);
/* rbb block queue API */
rt_size_t rt_rbb_blk_queue_get(rt_rbb_t rbb, rt_size_t queue_data_len, rt_rbb_blk_queue_t blk_queue);
rt_size_t rt_rbb_blk_queue_len(rt_rbb_blk_queue_t blk_queue);
rt_uint8_t *rt_rbb_blk_queue_buf(rt_rbb_blk_queue_t blk_queue);
void rt_rbb_blk_queue_free(rt_rbb_t rbb, rt_rbb_blk_queue_t blk_queue);
rt_size_t rt_rbb_next_blk_queue_len(rt_rbb_t rbb);
#ifdef __cplusplus
}
#endif
#endif /* _RINGBLK_BUF_H_ */

View File

@ -35,6 +35,7 @@
#include "ipc/waitqueue.h" #include "ipc/waitqueue.h"
#include "ipc/pipe.h" #include "ipc/pipe.h"
#include "ipc/poll.h" #include "ipc/poll.h"
#include "ipc/ringblk_buf.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View File

@ -0,0 +1,534 @@
/*
* File : ringblk_buf.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-08-25 armink the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
/**
* ring block buffer object initialization
*
* @param rbb ring block buffer object
* @param buf buffer
* @param buf_size buffer size
* @param block_set
* @param blk_max_num
*/
void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num)
{
rt_size_t i;
RT_ASSERT(rbb);
RT_ASSERT(buf);
RT_ASSERT(block_set);
rbb->buf = buf;
rbb->buf_size = buf_size;
rbb->blk_set = block_set;
rbb->blk_max_num = blk_max_num;
rt_slist_init(&rbb->blk_list);
/* initialize block status */
for (i = 0; i < blk_max_num; i++)
{
block_set[i].status = RT_RBB_BLK_UNUSED;
}
}
RTM_EXPORT(rt_rbb_init);
/**
* ring block buffer object create
*
* @param buf_size buffer size
* @param blk_max_num max block number
*
* @return != NULL: ring block buffer object
* NULL: create failed
*/
rt_rbb_t rt_rbb_create(rt_size_t buf_size, rt_size_t blk_max_num)
{
rt_rbb_t rbb = NULL;
rt_uint8_t *buf;
rt_rbb_blk_t blk_set;
rbb = (rt_rbb_t)rt_malloc(sizeof(struct rt_rbb));
if (!rbb)
{
return NULL;
}
buf = (rt_uint8_t *)rt_malloc(buf_size);
if (!buf)
{
rt_free(rbb);
return NULL;
}
blk_set = (rt_rbb_blk_t)rt_malloc(sizeof(struct rt_rbb_blk) * blk_max_num);
if (!blk_set)
{
rt_free(buf);
rt_free(rbb);
return NULL;
}
rt_rbb_init(rbb, buf, buf_size, blk_set, blk_max_num);
return rbb;
}
RTM_EXPORT(rt_rbb_create);
/**
* ring block buffer object destroy
*
* @param rbb ring block buffer object
*/
void rt_rbb_destroy(rt_rbb_t rbb)
{
RT_ASSERT(rbb);
rt_free(rbb);
rt_free(rbb->buf);
rt_free(rbb->blk_set);
}
RTM_EXPORT(rt_rbb_destroy);
static rt_rbb_blk_t find_empty_blk_in_set(rt_rbb_t rbb)
{
rt_size_t i;
RT_ASSERT(rbb);
for (i = 0; i < rbb->blk_max_num; i ++)
{
if (rbb->blk_set[i].status == RT_RBB_BLK_UNUSED)
{
return &rbb->blk_set[i];
}
}
return NULL;
}
/**
* Allocate a block by given size. The block will add to blk_list when allocate success.
*
* @param rbb ring block buffer object
* @param blk_size block size
*
* @return != NULL: allocated block
* NULL: allocate failed
*/
rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size)
{
rt_base_t level;
rt_size_t empty1 = 0, empty2 = 0;
rt_rbb_blk_t head, tail, new = NULL;
RT_ASSERT(rbb);
RT_ASSERT(blk_size < 1L << 24);
level = rt_hw_interrupt_disable();
new = find_empty_blk_in_set(rbb);
if (rt_slist_len(&rbb->blk_list) < rbb->blk_max_num && new)
{
if (rt_slist_len(&rbb->blk_list) > 0)
{
head = rt_slist_first_entry(&rbb->blk_list, struct rt_rbb_blk, list);
tail = rt_slist_tail_entry(&rbb->blk_list, struct rt_rbb_blk, list);
if (head->buf <= tail->buf)
{
/**
* head tail
* +--------------------------------------+-----------------+------------------+
* | empty2 | block1 | block2 | block3 | empty1 |
* +--------------------------------------+-----------------+------------------+
* rbb->buf
*/
empty1 = (rbb->buf + rbb->buf_size) - (tail->buf + tail->size);
empty2 = head->buf - rbb->buf;
if (empty1 >= blk_size)
{
rt_slist_append(&rbb->blk_list, &new->list);
new->status = RT_RBB_BLK_INITED;
new->buf = tail->buf + tail->size;
new->size = blk_size;
}
else if (empty2 >= blk_size)
{
rt_slist_append(&rbb->blk_list, &new->list);
new->status = RT_RBB_BLK_INITED;
new->buf = rbb->buf;
new->size = blk_size;
}
else
{
/* no space */
new = NULL;
}
}
else
{
/**
* tail head
* +----------------+-------------------------------------+--------+-----------+
* | block3 | empty1 | block1 | block2 |
* +----------------+-------------------------------------+--------+-----------+
* rbb->buf
*/
empty1 = head->buf - (tail->buf + tail->size);
if (empty1 >= blk_size)
{
rt_slist_append(&rbb->blk_list, &new->list);
new->status = RT_RBB_BLK_INITED;
new->buf = tail->buf + tail->size;
new->size = blk_size;
}
else
{
/* no space */
new = NULL;
}
}
}
else
{
/* the list is empty */
rt_slist_append(&rbb->blk_list, &new->list);
new->status = RT_RBB_BLK_INITED;
new->buf = rbb->buf;
new->size = blk_size;
}
}
else
{
new = NULL;
}
rt_hw_interrupt_enable(level);
return new;
}
RTM_EXPORT(rt_rbb_blk_alloc);
/**
* put a block to ring block buffer object
*
* @param block the block
*/
void rt_rbb_blk_put(rt_rbb_blk_t block)
{
RT_ASSERT(block);
RT_ASSERT(block->status == RT_RBB_BLK_INITED);
block->status = RT_RBB_BLK_PUT;
}
RTM_EXPORT(rt_rbb_blk_put);
/**
* get a block from the ring block buffer object
*
* @param rbb ring block buffer object
*
* @return != NULL: block
* NULL: get failed
*/
rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb)
{
rt_base_t level;
rt_rbb_blk_t block = NULL;
rt_slist_t *node;
RT_ASSERT(rbb);
if (rt_slist_isempty(&rbb->blk_list))
return 0;
level = rt_hw_interrupt_disable();
for (node = rt_slist_first(&rbb->blk_list); node; node = rt_slist_next(node))
{
block = rt_slist_entry(node, struct rt_rbb_blk, list);
if (block->status == RT_RBB_BLK_PUT)
{
block->status = RT_RBB_BLK_GET;
goto __exit;
}
}
/* not found */
block = NULL;
__exit:
rt_hw_interrupt_enable(level);
return block;
}
RTM_EXPORT(rt_rbb_blk_get);
/**
* free the block
*
* @param rbb ring block buffer object
* @param block the block
*/
void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block)
{
rt_base_t level;
RT_ASSERT(rbb);
RT_ASSERT(block);
RT_ASSERT(block->status != RT_RBB_BLK_UNUSED);
level = rt_hw_interrupt_disable();
/* remove it on rbb block list */
rt_slist_remove(&rbb->blk_list, &block->list);
block->status = RT_RBB_BLK_UNUSED;
rt_hw_interrupt_enable(level);
}
RTM_EXPORT(rt_rbb_blk_free);
/**
* get a continuous block to queue by given size
*
* tail head
* +------------------+---------------+--------+----------+--------+
* | block3 | empty1 | block1 | block2 |fragment|
* +------------------+------------------------+----------+--------+
* |<-- return_size -->| |
* |<--- queue_data_len --->|
*
* tail head
* +------------------+---------------+--------+----------+--------+
* | block3 | empty1 | block1 | block2 |fragment|
* +------------------+------------------------+----------+--------+
* |<-- return_size -->| out of len(b1+b2+b3) |
* |<-------------------- queue_data_len -------------------->|
*
* @param rbb ring block buffer object
* @param queue_data_len The max queue data size, and the return size must less then it.
* @param queue continuous block queue
*
* @return the block queue data total size
*/
rt_size_t rt_rbb_blk_queue_get(rt_rbb_t rbb, rt_size_t queue_data_len, rt_rbb_blk_queue_t blk_queue)
{
rt_base_t level;
rt_size_t data_total_size = 0;
rt_slist_t *node;
rt_rbb_blk_t last_block = NULL, block;
RT_ASSERT(rbb);
RT_ASSERT(blk_queue);
if (rt_slist_isempty(&rbb->blk_list))
return 0;
level = rt_hw_interrupt_disable();
for (node = rt_slist_first(&rbb->blk_list); node; node = rt_slist_next(node))
{
if (!last_block)
{
last_block = rt_slist_entry(node, struct rt_rbb_blk, list);
if (last_block->status == RT_RBB_BLK_PUT)
{
/* save the first put status block to queue */
blk_queue->blocks = last_block;
blk_queue->blk_num = 0;
}
else
{
/* the first block must be put status */
last_block = NULL;
continue;
}
}
else
{
block = rt_slist_entry(node, struct rt_rbb_blk, list);
/*
* these following conditions will break the loop:
* 1. the current block is not put status
* 2. the last block and current block is not continuous
* 3. the data_total_size will out of range
*/
if (block->status != RT_RBB_BLK_PUT ||
last_block->buf > block->buf ||
data_total_size + block->size > queue_data_len)
{
break;
}
/* backup last block */
last_block = block;
}
/* remove current block */
rt_slist_remove(&rbb->blk_list, &last_block->list);
data_total_size += last_block->size;
last_block->status = RT_RBB_BLK_GET;
blk_queue->blk_num++;
}
rt_hw_interrupt_enable(level);
return data_total_size;
}
RTM_EXPORT(rt_rbb_blk_queue_get);
/**
* get all block length on block queue
*
* @param blk_queue the block queue
*
* @return total length
*/
rt_size_t rt_rbb_blk_queue_len(rt_rbb_blk_queue_t blk_queue)
{
rt_size_t i, data_total_size = 0;
RT_ASSERT(blk_queue);
for (i = 0; i < blk_queue->blk_num; i++)
{
data_total_size += blk_queue->blocks[i].size;
}
return data_total_size;
}
RTM_EXPORT(rt_rbb_blk_queue_len);
/**
* return the block queue buffer
*
* @param blk_queue the block queue
*
* @return block queue buffer
*/
rt_uint8_t *rt_rbb_blk_queue_buf(rt_rbb_blk_queue_t blk_queue)
{
RT_ASSERT(blk_queue);
return blk_queue->blocks[0].buf;
}
RTM_EXPORT(rt_rbb_blk_queue_buf);
/**
* free the block queue
*
* @param rbb ring block buffer object
* @param blk_queue the block queue
*/
void rt_rbb_blk_queue_free(rt_rbb_t rbb, rt_rbb_blk_queue_t blk_queue)
{
rt_size_t i;
RT_ASSERT(rbb);
RT_ASSERT(blk_queue);
for (i = 0; i < blk_queue->blk_num; i++)
{
rt_rbb_blk_free(rbb, &blk_queue->blocks[i]);
}
}
RTM_EXPORT(rt_rbb_blk_queue_free);
/**
* The put status and buffer continuous blocks can be make a block queue.
* This function will return the length which from next can be make block queue.
*
* @param rbb ring block buffer object
*
* @return the next can be make block queue's length
*/
rt_size_t rt_rbb_next_blk_queue_len(rt_rbb_t rbb)
{
rt_base_t level;
rt_size_t data_len = 0;
rt_slist_t *node;
rt_rbb_blk_t last_block = NULL, block;
RT_ASSERT(rbb);
if (rt_slist_isempty(&rbb->blk_list))
return 0;
level = rt_hw_interrupt_disable();
for (node = rt_slist_first(&rbb->blk_list); node; node = rt_slist_next(node))
{
if (!last_block)
{
last_block = rt_slist_entry(node, struct rt_rbb_blk, list);
if (last_block->status != RT_RBB_BLK_PUT)
{
/* the first block must be put status */
last_block = NULL;
continue;
}
}
else
{
block = rt_slist_entry(node, struct rt_rbb_blk, list);
/*
* these following conditions will break the loop:
* 1. the current block is not put status
* 2. the last block and current block is not continuous
*/
if (block->status != RT_RBB_BLK_PUT || last_block->buf > block->buf)
{
break;
}
/* backup last block */
last_block = block;
}
data_len += last_block->size;
}
rt_hw_interrupt_enable(level);
return data_len;
}
RTM_EXPORT(rt_rbb_next_blk_queue_len);
/**
* get the ring block buffer object buffer size
*
* @param rbb ring block buffer object
*
* @return buffer size
*/
rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb)
{
RT_ASSERT(rbb);
return rbb->buf_size;
}
RTM_EXPORT(rt_rbb_get_buf_size);

341
examples/test/rbb_test.c Normal file
View File

@ -0,0 +1,341 @@
/*
* File : rbb_test.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2018-08-31 armink the first version
*/
#include <string.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
static rt_bool_t put_finish = RT_FALSE;
static void put_thread(void *param)
{
rt_rbb_t rbb = (rt_rbb_t)param;
rt_rbb_blk_t block;
rt_uint8_t put_count = 0;
put_finish = RT_FALSE;
while (put_count < 255)
{
if (put_count == 10)
{
put_count = 10;
}
block = rt_rbb_blk_alloc(rbb, rand() % 10 + 1);
if (block)
{
block->buf[0] = put_count++;
rt_rbb_blk_put(block);
}
rt_thread_mdelay(rand() % 10);
}
rt_kprintf("Put block data finish.\n");
put_finish = RT_TRUE;
}
static void get_thread(void *param)
{
rt_rbb_t rbb = (rt_rbb_t)param;
rt_rbb_blk_t block;
rt_uint8_t get_count = 0;
while (get_count < 255)
{
if (get_count == 10)
{
get_count = 10;
}
block = rt_rbb_blk_get(rbb);
if (block)
{
if (block->buf[0] != get_count++)
{
rt_kprintf("Error: get data (times %d) has an error!\n", get_count);
}
rt_rbb_blk_free(rbb, block);
}
else if (put_finish)
{
break;
}
rt_thread_mdelay(rand() % 10);
}
rt_kprintf("Get block data finish.\n");
rt_kprintf("\n====================== rbb dynamic test finish =====================\n");
}
void rbb_test(void)
{
rt_rbb_t rbb;
rt_rbb_blk_t blk1, blk2, blk3, blk4, blk5, blk6, _blk1, _blk2;
rt_size_t i, j, k, req_size, size;
struct rt_rbb_blk_queue blk_queue1;
rt_thread_t thread;
/* create ring block buffer */
rt_kprintf("\n====================== rbb create test =====================\n");
rbb = rt_rbb_create(52, 6);
if (rbb)
{
rt_kprintf("6 blocks in 52 bytes ring block buffer object create success.\n");
}
else
{
rt_kprintf("Test error: 6 blocks in 52 bytes ring block buffer object create failed.\n");
}
/* allocate block */
rt_kprintf("\n====================== rbb alloc test =====================\n");
blk1 = rt_rbb_blk_alloc(rbb, 2);
if (blk1 && blk1->size == 2)
{
memset(blk1->buf, 1, blk1->size);
rt_kprintf("Block1 (2 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block1 (2 bytes) allocate failed.\n");
goto __exit;
}
blk2 = rt_rbb_blk_alloc(rbb, 4);
if (blk2 && blk2->size == 4)
{
memset(blk2->buf, 2, blk2->size);
rt_kprintf("Block2 (4 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block2 (4 bytes) allocate failed.\n");
goto __exit;
}
blk3 = rt_rbb_blk_alloc(rbb, 8);
if (blk3 && blk3->size == 8)
{
memset(blk3->buf, 3, blk3->size);
rt_kprintf("Block3 (8 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block3 (8 bytes) allocate failed.\n");
goto __exit;
}
blk4 = rt_rbb_blk_alloc(rbb, 16);
if (blk4 && blk4->size == 16)
{
memset(blk4->buf, 4, blk4->size);
rt_kprintf("Block4 (16 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block4 (16 bytes) allocate failed.\n");
goto __exit;
}
blk5 = rt_rbb_blk_alloc(rbb, 32);
if (blk5 && blk5->size == 32)
{
memset(blk5->buf, 5, blk5->size);
rt_kprintf("Block5 (32 bytes) allocate success.\n");
}
else
{
rt_kprintf("Block5 (32 bytes) allocate failed.\n");
}
blk5 = rt_rbb_blk_alloc(rbb, 18);
if (blk5 && blk5->size == 18)
{
memset(blk5->buf, 5, blk5->size);
rt_kprintf("Block5 (18 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block5 (18 bytes) allocate failed.\n");
goto __exit;
}
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<- 2 -->|<-- 4 -->|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| blcok1 | block2 | block3 | block4 | block5 | empty |\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| inited | inited | inited | inited | inited | |\n");
/* put block */
rt_kprintf("\n====================== rbb put test =====================\n");
rt_rbb_blk_put(blk1);
rt_rbb_blk_put(blk2);
rt_rbb_blk_put(blk3);
rt_rbb_blk_put(blk4);
rt_rbb_blk_put(blk5);
rt_kprintf("Block1 to block5 put success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<- 2 -->|<-- 4 -->|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| blcok1 | block2 | block3 | block4 | block5 | empty |\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| put | put | put | put | put | |\n");
/* get block */
rt_kprintf("\n====================== rbb get test =====================\n");
_blk1 = rt_rbb_blk_get(rbb);
_blk2 = rt_rbb_blk_get(rbb);
for (i = 0; i < _blk1->size; i++)
{
if (_blk1->buf[i] != 1) break;
}
for (j = 0; j < _blk2->size; j++)
{
if (_blk2->buf[j] != 2) break;
}
if (blk1 == _blk1 && blk2 == _blk2 && i == _blk1->size && j == _blk2->size)
{
rt_kprintf("Block1 and block2 get success.\n");
}
else
{
rt_kprintf("Test error: block1 and block2 get failed.\n");
goto __exit;
}
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<- 2 -->|<-- 4 -->|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| blcok1 | block2 | block3 | block4 | block5 | empty |\n");
rt_kprintf("+--------+---------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| get | get | put | put | put | |\n");
/* free block */
rt_kprintf("\n====================== rbb free test =====================\n");
rt_rbb_blk_free(rbb, blk2);
rt_kprintf("Block2 free success.\n");
rt_rbb_blk_free(rbb, blk1);
rt_kprintf("Block1 free success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<------- 6 ------>|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+------------------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| empty2 | block3 | block4 | block5 | empty1 |\n");
rt_kprintf("+------------------+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| | put | put | put | |\n");
blk6 = rt_rbb_blk_alloc(rbb, 5);
if (blk6)
{
rt_kprintf("Block6 (5 bytes) allocate success.\n");
}
else
{
rt_kprintf("Test error: block6 (5 bytes) allocate failed.\n");
goto __exit;
}
rt_rbb_blk_put(blk6);
rt_kprintf("Block6 put success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<--- 5 ---->|< 1 >|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| block6 |empty| block3 | block4 | block5 | fragment |\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| put | | put | put | put | |\n");
/* get block queue */
rt_kprintf("\n====================== rbb block queue get test =====================\n");
req_size = rt_rbb_next_blk_queue_len(rbb) + 5;
size = rt_rbb_blk_queue_get(rbb, req_size, &blk_queue1);
i = j = k = 0;
for (; i < blk3->size; i++)
{
if (rt_rbb_blk_queue_buf(&blk_queue1)[i] != 3) break;
}
for (; j < blk4->size; j++)
{
if (rt_rbb_blk_queue_buf(&blk_queue1)[i + j] != 4) break;
}
for (; k < blk5->size; k++)
{
if (rt_rbb_blk_queue_buf(&blk_queue1)[i + j + k] != 5) break;
}
if (size && size == 42 && rt_rbb_blk_queue_len(&blk_queue1) == 42 && k == blk5->size)
{
rt_kprintf("Block queue (request %d bytes, actual %d) get success.\n", req_size, size);
}
else
{
rt_kprintf("Test error: Block queue (request %d bytes, actual %d) get failed.\n", req_size, size);
goto __exit;
}
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("| | |<----- block queue1 (42 bytes continuous buffer) ----->| |\n");
rt_kprintf("|<--- 5 ---->|< 1 >|<---- 8 ----->|<------- 16 -------->|<------ 18 ------>|<---- 4 ---->|\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| block6 |empty| block3 | block4 | block5 | fragment |\n");
rt_kprintf("+------------+-----+--------------+---------------------+------------------+-------------+\n");
rt_kprintf("| put | | get | get | get | |\n");
/* free block queue */
rt_kprintf("\n====================== rbb block queue free test =====================\n");
rt_rbb_blk_queue_free(rbb, &blk_queue1);
rt_kprintf("Block queue1 free success.\n");
rt_kprintf("Ring block buffer current status:\n");
rt_kprintf("next block queue length: %d\n", rt_rbb_next_blk_queue_len(rbb));
rt_kprintf("block list length: %d\n", rt_slist_len(&rbb->blk_list));
rt_kprintf("|<--- 5 ---->|<--------------------------------- 47 ------------------------------------>|\n");
rt_kprintf("+------------+---------------------------------------------------------------------------+\n");
rt_kprintf("| block6 | empty |\n");
rt_kprintf("+------------+---------------------------------------------------------------------------+\n");
rt_kprintf("| put | |\n");
rt_rbb_blk_free(rbb, blk6);
rt_kprintf("\n====================== rbb static test SUCCESS =====================\n");
rt_kprintf("\n====================== rbb dynamic test =====================\n");
thread = rt_thread_create("rbb_put", put_thread, rbb, 1024, 10, 25);
if (thread)
{
rt_thread_startup(thread);
}
thread = rt_thread_create("rbb_get", get_thread, rbb, 1024, 10, 25);
if (thread)
{
rt_thread_startup(thread);
}
__exit :
rt_rbb_destroy(rbb);
}
MSH_CMD_EXPORT(rbb_test, run ring block buffer testcase)