1、【增加】RT-Thread 系统 Demo。

Signed-off-by: armink <armink.ztl@gmail.com>
This commit is contained in:
armink
2017-04-15 15:14:49 +08:00
parent cee09e4a57
commit b536a063d6
247 changed files with 137359 additions and 2 deletions
@@ -0,0 +1,8 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd + '/../include']
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE_IPC'], CPPPATH = CPPPATH)
Return('group')
@@ -0,0 +1,141 @@
/*
* File : completion.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, 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
* 2012-09-30 Bernard first version.
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#define RT_COMPLETED 1
#define RT_UNCOMPLETED 0
void rt_completion_init(struct rt_completion *completion)
{
rt_base_t level;
RT_ASSERT(completion != RT_NULL);
level = rt_hw_interrupt_disable();
completion->flag = RT_UNCOMPLETED;
rt_list_init(&completion->suspended_list);
rt_hw_interrupt_enable(level);
}
rt_err_t rt_completion_wait(struct rt_completion *completion,
rt_int32_t timeout)
{
rt_err_t result;
rt_base_t level;
rt_thread_t thread;
RT_ASSERT(completion != RT_NULL);
result = RT_EOK;
thread = rt_thread_self();
level = rt_hw_interrupt_disable();
if (completion->flag != RT_COMPLETED)
{
/* only one thread can suspend on complete */
RT_ASSERT(rt_list_isempty(&(completion->suspended_list)));
if (timeout == 0)
{
result = -RT_ETIMEOUT;
goto __exit;
}
else
{
/* reset thread error number */
thread->error = RT_EOK;
/* suspend thread */
rt_thread_suspend(thread);
/* add to suspended list */
rt_list_insert_before(&(completion->suspended_list),
&(thread->tlist));
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
/* start timer */
if (timeout > 0)
{
/* reset the timeout of thread timer and start it */
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
rt_timer_start(&(thread->thread_timer));
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
/* do schedule */
rt_schedule();
/* thread is waked up */
result = thread->error;
level = rt_hw_interrupt_disable();
/* clean completed flag */
completion->flag = RT_UNCOMPLETED;
}
}
__exit:
rt_hw_interrupt_enable(level);
return result;
}
void rt_completion_done(struct rt_completion *completion)
{
rt_base_t level;
RT_ASSERT(completion != RT_NULL);
if (completion->flag == RT_COMPLETED)
return;
level = rt_hw_interrupt_disable();
completion->flag = RT_COMPLETED;
if (!rt_list_isempty(&(completion->suspended_list)))
{
/* there is one thread in suspended list */
struct rt_thread *thread;
/* get thread entry */
thread = rt_list_entry(completion->suspended_list.next,
struct rt_thread,
tlist);
/* resume it */
rt_thread_resume(thread);
rt_hw_interrupt_enable(level);
/* perform a schedule */
rt_schedule();
}
else
{
rt_hw_interrupt_enable(level);
}
}
@@ -0,0 +1,353 @@
/*
* File : dataqueue.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, 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
* 2012-09-30 Bernard first version.
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <rthw.h>
struct rt_data_item
{
const void *data_ptr;
rt_size_t data_size;
};
rt_err_t
rt_data_queue_init(struct rt_data_queue *queue,
rt_uint16_t size,
rt_uint16_t lwm,
void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event))
{
RT_ASSERT(queue != RT_NULL);
queue->evt_notify = evt_notify;
queue->size = size;
queue->lwm = lwm;
queue->waiting_lwm = RT_FALSE;
queue->get_index = 0;
queue->put_index = 0;
rt_list_init(&(queue->suspended_push_list));
rt_list_init(&(queue->suspended_pop_list));
queue->queue = (struct rt_data_item *)rt_malloc(sizeof(struct rt_data_item) * size);
if (queue->queue == RT_NULL)
{
return -RT_ENOMEM;
}
return RT_EOK;
}
RTM_EXPORT(rt_data_queue_init);
rt_err_t rt_data_queue_push(struct rt_data_queue *queue,
const void *data_ptr,
rt_size_t data_size,
rt_int32_t timeout)
{
rt_uint16_t mask;
rt_ubase_t level;
rt_thread_t thread;
rt_err_t result;
RT_ASSERT(queue != RT_NULL);
result = RT_EOK;
thread = rt_thread_self();
mask = queue->size - 1;
level = rt_hw_interrupt_disable();
while (queue->put_index - queue->get_index == queue->size)
{
queue->waiting_lwm = RT_TRUE;
/* queue is full */
if (timeout == 0)
{
result = -RT_ETIMEOUT;
goto __exit;
}
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
/* reset thread error number */
thread->error = RT_EOK;
/* suspend thread on the push list */
rt_thread_suspend(thread);
rt_list_insert_before(&(queue->suspended_push_list), &(thread->tlist));
/* start timer */
if (timeout > 0)
{
/* reset the timeout of thread timer and start it */
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
rt_timer_start(&(thread->thread_timer));
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
/* do schedule */
rt_schedule();
/* thread is waked up */
result = thread->error;
level = rt_hw_interrupt_disable();
if (result != RT_EOK) goto __exit;
}
queue->queue[queue->put_index & mask].data_ptr = data_ptr;
queue->queue[queue->put_index & mask].data_size = data_size;
queue->put_index += 1;
if (!rt_list_isempty(&(queue->suspended_pop_list)))
{
/* there is at least one thread in suspended list */
/* get thread entry */
thread = rt_list_entry(queue->suspended_pop_list.next,
struct rt_thread,
tlist);
/* resume it */
rt_thread_resume(thread);
rt_hw_interrupt_enable(level);
/* perform a schedule */
rt_schedule();
return result;
}
__exit:
rt_hw_interrupt_enable(level);
if ((result == RT_EOK) && queue->evt_notify != RT_NULL)
{
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_PUSH);
}
return result;
}
RTM_EXPORT(rt_data_queue_push);
rt_err_t rt_data_queue_pop(struct rt_data_queue *queue,
const void** data_ptr,
rt_size_t *size,
rt_int32_t timeout)
{
rt_ubase_t level;
rt_thread_t thread;
rt_err_t result;
rt_uint16_t mask;
RT_ASSERT(queue != RT_NULL);
RT_ASSERT(data_ptr != RT_NULL);
RT_ASSERT(size != RT_NULL);
result = RT_EOK;
thread = rt_thread_self();
mask = queue->size - 1;
level = rt_hw_interrupt_disable();
while (queue->get_index == queue->put_index)
{
/* queue is empty */
if (timeout == 0)
{
result = -RT_ETIMEOUT;
goto __exit;
}
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
/* reset thread error number */
thread->error = RT_EOK;
/* suspend thread on the pop list */
rt_thread_suspend(thread);
rt_list_insert_before(&(queue->suspended_pop_list), &(thread->tlist));
/* start timer */
if (timeout > 0)
{
/* reset the timeout of thread timer and start it */
rt_timer_control(&(thread->thread_timer),
RT_TIMER_CTRL_SET_TIME,
&timeout);
rt_timer_start(&(thread->thread_timer));
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
/* do schedule */
rt_schedule();
/* thread is waked up */
result = thread->error;
level = rt_hw_interrupt_disable();
if (result != RT_EOK)
goto __exit;
}
*data_ptr = queue->queue[queue->get_index & mask].data_ptr;
*size = queue->queue[queue->get_index & mask].data_size;
queue->get_index += 1;
if ((queue->waiting_lwm == RT_TRUE) &&
(queue->put_index - queue->get_index) <= queue->lwm)
{
queue->waiting_lwm = RT_FALSE;
/*
* there is at least one thread in suspended list
* and less than low water mark
*/
if (!rt_list_isempty(&(queue->suspended_push_list)))
{
/* get thread entry */
thread = rt_list_entry(queue->suspended_push_list.next,
struct rt_thread,
tlist);
/* resume it */
rt_thread_resume(thread);
rt_hw_interrupt_enable(level);
/* perform a schedule */
rt_schedule();
}
if (queue->evt_notify != RT_NULL)
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_LWM);
return result;
}
__exit:
rt_hw_interrupt_enable(level);
if ((result == RT_EOK) && (queue->evt_notify != RT_NULL))
{
queue->evt_notify(queue, RT_DATAQUEUE_EVENT_POP);
}
return result;
}
RTM_EXPORT(rt_data_queue_pop);
rt_err_t rt_data_queue_peak(struct rt_data_queue *queue,
const void** data_ptr,
rt_size_t *size)
{
rt_ubase_t level;
rt_uint16_t mask;
RT_ASSERT(queue != RT_NULL);
mask = queue->size - 1;
level = rt_hw_interrupt_disable();
if (queue->get_index == queue->put_index)
{
rt_hw_interrupt_enable(level);
return -RT_EEMPTY;
}
*data_ptr = queue->queue[queue->get_index & mask].data_ptr;
*size = queue->queue[queue->get_index & mask].data_size;
rt_hw_interrupt_enable(level);
return RT_EOK;
}
RTM_EXPORT(rt_data_queue_peak);
void rt_data_queue_reset(struct rt_data_queue *queue)
{
struct rt_thread *thread;
register rt_ubase_t temp;
rt_enter_critical();
/* wakeup all suspend threads */
/* resume on pop list */
while (!rt_list_isempty(&(queue->suspended_pop_list)))
{
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* get next suspend thread */
thread = rt_list_entry(queue->suspended_pop_list.next,
struct rt_thread,
tlist);
/* set error code to RT_ERROR */
thread->error = -RT_ERROR;
/*
* resume thread
* In rt_thread_resume function, it will remove current thread from
* suspend list
*/
rt_thread_resume(thread);
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
/* resume on push list */
while (!rt_list_isempty(&(queue->suspended_push_list)))
{
/* disable interrupt */
temp = rt_hw_interrupt_disable();
/* get next suspend thread */
thread = rt_list_entry(queue->suspended_push_list.next,
struct rt_thread,
tlist);
/* set error code to RT_ERROR */
thread->error = -RT_ERROR;
/*
* resume thread
* In rt_thread_resume function, it will remove current thread from
* suspend list
*/
rt_thread_resume(thread);
/* enable interrupt */
rt_hw_interrupt_enable(temp);
}
rt_exit_critical();
rt_schedule();
}
RTM_EXPORT(rt_data_queue_reset);
@@ -0,0 +1,293 @@
/*
* File : pipe.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, 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
* 2012-09-30 Bernard first version.
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
static void _rt_pipe_resume_writer(struct rt_pipe_device *pipe)
{
if (!rt_list_isempty(&pipe->suspended_write_list))
{
rt_thread_t thread;
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_WR);
/* get suspended thread */
thread = rt_list_entry(pipe->suspended_write_list.next,
struct rt_thread,
tlist);
/* resume the write thread */
rt_thread_resume(thread);
rt_schedule();
}
}
static rt_size_t rt_pipe_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
rt_uint32_t level;
rt_thread_t thread;
struct rt_pipe_device *pipe;
rt_size_t read_nbytes;
pipe = PIPE_DEVICE(dev);
RT_ASSERT(pipe != RT_NULL);
if (!(pipe->flag & RT_PIPE_FLAG_BLOCK_RD))
{
level = rt_hw_interrupt_disable();
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), buffer, size);
/* if the ringbuffer is empty, there won't be any writer waiting */
if (read_nbytes)
_rt_pipe_resume_writer(pipe);
rt_hw_interrupt_enable(level);
return read_nbytes;
}
thread = rt_thread_self();
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
do {
level = rt_hw_interrupt_disable();
read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), buffer, size);
if (read_nbytes == 0)
{
rt_thread_suspend(thread);
/* waiting on suspended read list */
rt_list_insert_before(&(pipe->suspended_read_list),
&(thread->tlist));
rt_hw_interrupt_enable(level);
rt_schedule();
}
else
{
_rt_pipe_resume_writer(pipe);
rt_hw_interrupt_enable(level);
break;
}
} while (read_nbytes == 0);
return read_nbytes;
}
static void _rt_pipe_resume_reader(struct rt_pipe_device *pipe)
{
if (pipe->parent.rx_indicate)
pipe->parent.rx_indicate(&pipe->parent,
rt_ringbuffer_data_len(&pipe->ringbuffer));
if (!rt_list_isempty(&pipe->suspended_read_list))
{
rt_thread_t thread;
RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_RD);
/* get suspended thread */
thread = rt_list_entry(pipe->suspended_read_list.next,
struct rt_thread,
tlist);
/* resume the read thread */
rt_thread_resume(thread);
rt_schedule();
}
}
static rt_size_t rt_pipe_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
rt_uint32_t level;
rt_thread_t thread;
struct rt_pipe_device *pipe;
rt_size_t write_nbytes;
pipe = PIPE_DEVICE(dev);
RT_ASSERT(pipe != RT_NULL);
if ((pipe->flag & RT_PIPE_FLAG_FORCE_WR) ||
!(pipe->flag & RT_PIPE_FLAG_BLOCK_WR))
{
level = rt_hw_interrupt_disable();
if (pipe->flag & RT_PIPE_FLAG_FORCE_WR)
write_nbytes = rt_ringbuffer_put_force(&(pipe->ringbuffer),
buffer, size);
else
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer),
buffer, size);
_rt_pipe_resume_reader(pipe);
rt_hw_interrupt_enable(level);
return write_nbytes;
}
thread = rt_thread_self();
/* current context checking */
RT_DEBUG_NOT_IN_INTERRUPT;
do {
level = rt_hw_interrupt_disable();
write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer), buffer, size);
if (write_nbytes == 0)
{
/* pipe full, waiting on suspended write list */
rt_thread_suspend(thread);
/* waiting on suspended read list */
rt_list_insert_before(&(pipe->suspended_write_list),
&(thread->tlist));
rt_hw_interrupt_enable(level);
rt_schedule();
}
else
{
_rt_pipe_resume_reader(pipe);
rt_hw_interrupt_enable(level);
break;
}
} while (write_nbytes == 0);
return write_nbytes;
}
static rt_err_t rt_pipe_control(rt_device_t dev, rt_uint8_t cmd, void *args)
{
if (cmd == PIPE_CTRL_GET_SPACE && args)
*(rt_size_t*)args = rt_ringbuffer_space_len(&PIPE_DEVICE(dev)->ringbuffer);
return RT_EOK;
}
/**
* This function will initialize a pipe device and put it under control of
* resource management.
*
* @param pipe the pipe device
* @param name the name of pipe device
* @param flag the attribute of the pipe device
* @param buf the buffer of pipe device
* @param size the size of pipe device buffer
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_pipe_init(struct rt_pipe_device *pipe,
const char *name,
enum rt_pipe_flag flag,
rt_uint8_t *buf,
rt_size_t size)
{
RT_ASSERT(pipe);
RT_ASSERT(buf);
/* initialize suspended list */
rt_list_init(&pipe->suspended_read_list);
rt_list_init(&pipe->suspended_write_list);
/* initialize ring buffer */
rt_ringbuffer_init(&pipe->ringbuffer, buf, size);
pipe->flag = flag;
/* create pipe */
pipe->parent.type = RT_Device_Class_Pipe;
pipe->parent.init = RT_NULL;
pipe->parent.open = RT_NULL;
pipe->parent.close = RT_NULL;
pipe->parent.read = rt_pipe_read;
pipe->parent.write = rt_pipe_write;
pipe->parent.control = rt_pipe_control;
return rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR);
}
RTM_EXPORT(rt_pipe_init);
/**
* This function will detach a pipe device from resource management
*
* @param pipe the pipe device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_pipe_detach(struct rt_pipe_device *pipe)
{
return rt_device_unregister(&pipe->parent);
}
RTM_EXPORT(rt_pipe_detach);
#ifdef RT_USING_HEAP
rt_err_t rt_pipe_create(const char *name, enum rt_pipe_flag flag, rt_size_t size)
{
rt_uint8_t *rb_memptr = RT_NULL;
struct rt_pipe_device *pipe = RT_NULL;
/* get aligned size */
size = RT_ALIGN(size, RT_ALIGN_SIZE);
pipe = (struct rt_pipe_device *)rt_calloc(1, sizeof(struct rt_pipe_device));
if (pipe == RT_NULL)
return -RT_ENOMEM;
/* create ring buffer of pipe */
rb_memptr = rt_malloc(size);
if (rb_memptr == RT_NULL)
{
rt_free(pipe);
return -RT_ENOMEM;
}
return rt_pipe_init(pipe, name, flag, rb_memptr, size);
}
RTM_EXPORT(rt_pipe_create);
void rt_pipe_destroy(struct rt_pipe_device *pipe)
{
if (pipe == RT_NULL)
return;
/* un-register pipe device */
rt_pipe_detach(pipe);
/* release memory */
rt_free(pipe->ringbuffer.buffer_ptr);
rt_free(pipe);
return;
}
RTM_EXPORT(rt_pipe_destroy);
#endif /* RT_USING_HEAP */
@@ -0,0 +1,256 @@
/*
* File : portal.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2013, 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
* 2013-08-19 Grissiom initial version
*/
#include <rtthread.h>
#include <rtdevice.h>
#define PT_WRITE_DEV(pt) (((struct rt_portal_device*)pt)->write_dev)
#define PT_READ_DEV(pt) (((struct rt_portal_device*)pt)->read_dev)
static rt_err_t _portal_init(rt_device_t dev)
{
rt_err_t err;
struct rt_portal_device *portal;
RT_ASSERT(dev);
portal = (struct rt_portal_device*)dev;
err = rt_device_init(portal->write_dev);
if (err != RT_EOK)
return err;
err = rt_device_init(portal->read_dev);
return err;
}
static rt_err_t _portal_open(rt_device_t dev, rt_uint16_t oflag)
{
rt_err_t err;
struct rt_portal_device *portal;
RT_ASSERT(dev);
if (!oflag)
return -RT_ERROR;
portal = (struct rt_portal_device*)dev;
if (oflag & RT_DEVICE_OFLAG_RDONLY)
{
err = rt_device_open(portal->read_dev, RT_DEVICE_OFLAG_RDONLY);
if (err != RT_EOK)
return err;
}
if (oflag & RT_DEVICE_OFLAG_WRONLY)
{
err = rt_device_open(portal->write_dev, RT_DEVICE_OFLAG_WRONLY);
if (err != RT_EOK)
return err;
}
return RT_EOK;
}
static rt_err_t _portal_close(rt_device_t dev)
{
struct rt_portal_device *portal;
RT_ASSERT(dev);
portal = (struct rt_portal_device*)dev;
rt_device_close(portal->write_dev);
rt_device_close(portal->read_dev);
return RT_EOK;
}
static rt_size_t _portal_read(rt_device_t dev,
rt_off_t pos,
void *buffer,
rt_size_t size)
{
return rt_device_read(PT_READ_DEV(dev),
pos, buffer, size);
}
static rt_size_t _portal_write(rt_device_t dev,
rt_off_t pos,
const void *buffer,
rt_size_t size)
{
return rt_device_write(PT_WRITE_DEV(dev),
pos, buffer, size);
}
static rt_err_t _portal_rx_indicate(rt_device_t dev, rt_size_t size)
{
struct rt_pipe_device *pipe;
RT_ASSERT(dev && dev->type == RT_Device_Class_Pipe);
pipe = (struct rt_pipe_device*)dev;
if (pipe->read_portal->parent.rx_indicate)
return pipe->read_portal->parent.rx_indicate(
(rt_device_t)pipe->read_portal, size);
return -RT_ENOSYS;
}
static rt_err_t _portal_tx_complete(rt_device_t dev, void *buf)
{
struct rt_pipe_device *pipe;
RT_ASSERT(dev && dev->type == RT_Device_Class_Pipe);
pipe = (struct rt_pipe_device*)dev;
if (pipe->write_portal->parent.tx_complete)
return pipe->write_portal->parent.tx_complete(
(rt_device_t)pipe->write_portal, buf);
return -RT_ENOSYS;
}
/**
* This function will initialize a portal device and put it under control of
* resource management.
*
* Portal is a device that connect devices
*
* Currently, you can only connect pipes in portal. Pipes are unidirectional.
* But with portal, you can construct a bidirectional device with two pipes.
* The inner connection is just like this:
*
* portal0 portal1
* read || || write
* <--<---||<---<---||<---<-- (pipe0)
* || ||
* -->--->||--->--->||--->--> (pipe1)
* write || || read
*
* You will always construct two portals on two pipes, say, "portal0" and
* "portal1". Data written into "portal0" can be retrieved in "portal1" and
* vice versa. `rx_indicate` and `tx_complete` events are propagated
* accordingly.
*
* @param portal the portal device
* @param portal_name the name of the portal device
* @param write_dev the name of the pipe device that this portal write into
* @param read_dev the name of the pipe device that this portal read from
*
* @return the operation status, RT_EOK on successful. -RT_ENOSYS on one pipe
* device could not be found.
*/
rt_err_t rt_portal_init(struct rt_portal_device *portal,
const char *portal_name,
const char *write_dev,
const char *read_dev)
{
rt_device_t dev;
RT_ASSERT(portal);
portal->parent.type = RT_Device_Class_Portal;
portal->parent.init = _portal_init;
portal->parent.open = _portal_open;
portal->parent.close = _portal_close;
portal->parent.write = _portal_write;
portal->parent.read = _portal_read;
/* single control of the two devices makes no sense */
portal->parent.control = RT_NULL;
dev = rt_device_find(write_dev);
if (dev == RT_NULL)
return -RT_ENOSYS;
RT_ASSERT(dev->type == RT_Device_Class_Pipe);
portal->write_dev = dev;
rt_device_set_tx_complete(&portal->parent, dev->tx_complete);
rt_device_set_tx_complete(dev, _portal_tx_complete);
((struct rt_pipe_device*)dev)->write_portal = portal;
dev = rt_device_find(read_dev);
if (dev == RT_NULL)
{
rt_device_set_tx_complete(dev, portal->parent.tx_complete);
return -RT_ENOSYS;
}
RT_ASSERT(dev->type == RT_Device_Class_Pipe);
portal->read_dev = dev;
rt_device_set_rx_indicate(&portal->parent, dev->rx_indicate);
rt_device_set_rx_indicate(dev, _portal_rx_indicate);
((struct rt_pipe_device*)dev)->read_portal = portal;
return rt_device_register(&(portal->parent),
portal_name,
RT_DEVICE_FLAG_RDWR);
}
RTM_EXPORT(rt_portal_init);
/**
* This function will detach a portal device from resource management
*
* @param portal the portal device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_portal_detach(struct rt_portal_device *portal)
{
return rt_device_unregister(&portal->parent);
}
RTM_EXPORT(rt_portal_detach);
#ifdef RT_USING_HEAP
rt_err_t rt_portal_create(const char *name,
const char *write_dev,
const char *read_dev)
{
struct rt_portal_device *portal;
portal = (struct rt_portal_device*)rt_calloc(1, sizeof(*portal));
if (portal == RT_NULL)
return -RT_ENOMEM;
return rt_portal_init(portal, name, write_dev, read_dev);
}
RTM_EXPORT(rt_portal_create);
void rt_portal_destroy(struct rt_portal_device *portal)
{
if (portal == RT_NULL)
return;
rt_portal_detach(portal);
rt_free(portal);
return;
}
RTM_EXPORT(rt_portal_destroy);
#endif /* RT_USING_HEAP */
@@ -0,0 +1,286 @@
/*
* File : ringbuffer.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2012, 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
* 2012-09-30 Bernard first version.
* 2013-05-08 Grissiom reimplement
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <string.h>
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
rt_uint8_t *pool,
rt_int16_t size)
{
RT_ASSERT(rb != RT_NULL);
RT_ASSERT(size > 0)
/* initialize read and write index */
rb->read_mirror = rb->read_index = 0;
rb->write_mirror = rb->write_index = 0;
/* set buffer pool and size */
rb->buffer_ptr = pool;
rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}
RTM_EXPORT(rt_ringbuffer_init);
/**
* put a block of data into ring buffer
*/
rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb,
const rt_uint8_t *ptr,
rt_uint16_t length)
{
rt_uint16_t size;
RT_ASSERT(rb != RT_NULL);
/* whether has enough space */
size = rt_ringbuffer_space_len(rb);
/* no space */
if (size == 0)
return 0;
/* drop some data */
if (size < length)
length = size;
if (rb->buffer_size - rb->write_index > length)
{
/* read_index - write_index = empty space */
memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->write_index += length;
return length;
}
memcpy(&rb->buffer_ptr[rb->write_index],
&ptr[0],
rb->buffer_size - rb->write_index);
memcpy(&rb->buffer_ptr[0],
&ptr[rb->buffer_size - rb->write_index],
length - (rb->buffer_size - rb->write_index));
/* we are going into the other side of the mirror */
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - (rb->buffer_size - rb->write_index);
return length;
}
RTM_EXPORT(rt_ringbuffer_put);
/**
* put a block of data into ring buffer
*
* When the buffer is full, it will discard the old data.
*/
rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
const rt_uint8_t *ptr,
rt_uint16_t length)
{
enum rt_ringbuffer_state old_state;
RT_ASSERT(rb != RT_NULL);
old_state = rt_ringbuffer_status(rb);
if (length > rb->buffer_size)
length = rb->buffer_size;
if (rb->buffer_size - rb->write_index > length)
{
/* read_index - write_index = empty space */
memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->write_index += length;
if (old_state == RT_RINGBUFFER_FULL)
rb->read_index = rb->write_index;
return length;
}
memcpy(&rb->buffer_ptr[rb->write_index],
&ptr[0],
rb->buffer_size - rb->write_index);
memcpy(&rb->buffer_ptr[0],
&ptr[rb->buffer_size - rb->write_index],
length - (rb->buffer_size - rb->write_index));
/* we are going into the other side of the mirror */
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - (rb->buffer_size - rb->write_index);
if (old_state == RT_RINGBUFFER_FULL)
{
rb->read_mirror = ~rb->read_mirror;
rb->read_index = rb->write_index;
}
return length;
}
RTM_EXPORT(rt_ringbuffer_put_force);
/**
* get data from ring buffer
*/
rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb,
rt_uint8_t *ptr,
rt_uint16_t length)
{
rt_size_t size;
RT_ASSERT(rb != RT_NULL);
/* whether has enough data */
size = rt_ringbuffer_data_len(rb);
/* no data */
if (size == 0)
return 0;
/* less data */
if (size < length)
length = size;
if (rb->buffer_size - rb->read_index > length)
{
/* copy all of data */
memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
/* this should not cause overflow because there is enough space for
* length of data in current mirror */
rb->read_index += length;
return length;
}
memcpy(&ptr[0],
&rb->buffer_ptr[rb->read_index],
rb->buffer_size - rb->read_index);
memcpy(&ptr[rb->buffer_size - rb->read_index],
&rb->buffer_ptr[0],
length - (rb->buffer_size - rb->read_index));
/* we are going into the other side of the mirror */
rb->read_mirror = ~rb->read_mirror;
rb->read_index = length - (rb->buffer_size - rb->read_index);
return length;
}
RTM_EXPORT(rt_ringbuffer_get);
/**
* put a character into ring buffer
*/
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
RT_ASSERT(rb != RT_NULL);
/* whether has enough space */
if (!rt_ringbuffer_space_len(rb))
return 0;
rb->buffer_ptr[rb->write_index] = ch;
/* flip mirror */
if (rb->write_index == rb->buffer_size-1)
{
rb->write_mirror = ~rb->write_mirror;
rb->write_index = 0;
}
else
{
rb->write_index++;
}
return 1;
}
RTM_EXPORT(rt_ringbuffer_putchar);
/**
* put a character into ring buffer
*
* When the buffer is full, it will discard one old data.
*/
rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
enum rt_ringbuffer_state old_state;
RT_ASSERT(rb != RT_NULL);
old_state = rt_ringbuffer_status(rb);
rb->buffer_ptr[rb->write_index] = ch;
/* flip mirror */
if (rb->write_index == rb->buffer_size-1)
{
rb->write_mirror = ~rb->write_mirror;
rb->write_index = 0;
if (old_state == RT_RINGBUFFER_FULL)
{
rb->read_mirror = ~rb->read_mirror;
rb->read_index = rb->write_index;
}
}
else
{
rb->write_index++;
if (old_state == RT_RINGBUFFER_FULL)
rb->read_index = rb->write_index;
}
return 1;
}
RTM_EXPORT(rt_ringbuffer_putchar_force);
/**
* get a character from a ringbuffer
*/
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{
RT_ASSERT(rb != RT_NULL);
/* ringbuffer is empty */
if (!rt_ringbuffer_data_len(rb))
return 0;
/* put character */
*ch = rb->buffer_ptr[rb->read_index];
if (rb->read_index == rb->buffer_size-1)
{
rb->read_mirror = ~rb->read_mirror;
rb->read_index = 0;
}
else
{
rb->read_index++;
}
return 1;
}
RTM_EXPORT(rt_ringbuffer_getchar);
@@ -0,0 +1,101 @@
#include <rtthread.h>
#include <rtdevice.h>
#ifdef RT_USING_HEAP
static void _workqueue_thread_entry(void* parameter)
{
struct rt_work* work;
struct rt_workqueue* queue;
queue = (struct rt_workqueue*) parameter;
RT_ASSERT(queue != RT_NULL);
while (1)
{
if (rt_list_isempty(&(queue->work_list)))
{
/* no software timer exist, suspend self. */
rt_thread_suspend(rt_thread_self());
rt_schedule();
}
/* we have work to do with. */
rt_enter_critical();
work = rt_list_entry(queue->work_list.next, struct rt_work, list);
rt_list_remove(&(work->list));
rt_exit_critical();
/* do work */
work->work_func(work, work->work_data);
}
}
struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority)
{
struct rt_workqueue *queue = RT_NULL;
queue = (struct rt_workqueue*)RT_KERNEL_MALLOC(sizeof(struct rt_workqueue));
if (queue != RT_NULL)
{
/* initialize work list */
rt_list_init(&(queue->work_list));
/* create the work thread */
queue->work_thread = rt_thread_create(name, _workqueue_thread_entry, queue, stack_size, priority, 10);
if (queue->work_thread == RT_NULL)
{
RT_KERNEL_FREE(queue);
return RT_NULL;
}
rt_thread_startup(queue->work_thread);
}
return queue;
}
rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue)
{
RT_ASSERT(queue != RT_NULL);
rt_thread_delete(queue->work_thread);
RT_KERNEL_FREE(queue);
return RT_EOK;
}
rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work)
{
RT_ASSERT(queue != RT_NULL);
RT_ASSERT(work != RT_NULL);
rt_enter_critical();
/* NOTE: the work MUST be initialized firstly */
rt_list_remove(&(work->list));
rt_list_insert_after(queue->work_list.prev, &(work->list));
if (queue->work_thread->stat != RT_THREAD_READY)
{
rt_exit_critical();
/* resume work thread */
rt_thread_resume(queue->work_thread);
rt_schedule();
}
else rt_exit_critical();
return RT_EOK;
}
rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work)
{
RT_ASSERT(queue != RT_NULL);
RT_ASSERT(work != RT_NULL);
rt_enter_critical();
rt_list_remove(&(work->list));
rt_exit_critical();
return RT_EOK;
}
#endif