diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 583c9afe07..32329578e3 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -5,6 +5,44 @@ #define RT_DEVICE(device) ((rt_device_t)device) +/* completion flag */ +struct rt_completion +{ + rt_uint32_t flag; + + /* suspended list */ + rt_list_t suspended_list; +}; + +/* ring buffer */ +struct rt_ringbuffer +{ + rt_uint16_t read_index, write_index; + rt_uint8_t *buffer_ptr; + rt_uint16_t buffer_size; +}; + +/** + * Completion + */ +void rt_completion_init(struct rt_completion* completion); +rt_err_t rt_completion_wait(struct rt_completion* completion, rt_int32_t timeout); +void rt_completion_done(struct rt_completion* completion); + +/** + * DataLink for DeviceDriver + */ + +/** + * RingBuffer for DeviceDriver + */ +void rt_ringbuffer_init(struct rt_ringbuffer* rb, rt_uint8_t *pool, rt_uint16_t size); +rt_size_t rt_ringbuffer_put(struct rt_ringbuffer* rb, const rt_uint8_t *ptr, rt_uint16_t length); +rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer* rb, const rt_uint8_t ch); +rt_size_t rt_ringbuffer_get(struct rt_ringbuffer* rb, rt_uint8_t *ptr, rt_uint16_t length); +rt_size_t rt_ringbuffer_available_size(struct rt_ringbuffer* rb); +rt_size_t rt_ringbuffer_emptry_size(struct rt_ringbuffer* rb); + #ifdef RT_USING_SPI #include "drivers/spi.h" #endif diff --git a/components/drivers/src/SConscript b/components/drivers/src/SConscript new file mode 100644 index 0000000000..00608451aa --- /dev/null +++ b/components/drivers/src/SConscript @@ -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') diff --git a/components/drivers/src/completion.c b/components/drivers/src/completion.c new file mode 100644 index 0000000000..a2f9a3058b --- /dev/null +++ b/components/drivers/src/completion.c @@ -0,0 +1,107 @@ +/** + * Complete implementation in Device Drivers + */ +#include +#include +#include + +#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 + { + /* 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); + + 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); + } +} diff --git a/components/drivers/src/ringbuffer.c b/components/drivers/src/ringbuffer.c new file mode 100644 index 0000000000..6872c19dc3 --- /dev/null +++ b/components/drivers/src/ringbuffer.c @@ -0,0 +1,154 @@ +#include +#include + +void rt_ringbuffer_init(struct rt_ringbuffer* rb, rt_uint8_t *pool, rt_uint16_t size) +{ + RT_ASSERT(rb != RT_NULL); + + /* initialize read and write index */ + rb->read_index = rb->write_index = 0; + + /* set buffer pool and size */ + rb->buffer_ptr = pool; + rb->buffer_size = size; +} + +rt_size_t rt_ringbuffer_put(struct rt_ringbuffer* rb, const rt_uint8_t *ptr, rt_uint16_t length) +{ + rt_size_t size; + + RT_ASSERT(rb != RT_NULL); + + /* whether has enough space */ + if (rb->read_index > rb->write_index) + size = rb->read_index - rb->write_index; + else + size = rb->buffer_size - rb->write_index + rb->read_index; + + /* no space */ + if (size == 0) return 0; + + /* drop some data */ + if (size < length) length = size; + + if (rb->read_index > rb->write_index) + { + /* read_index - write_index = empty space */ + rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length); + rb->write_index += length; + } + else + { + if (rb->buffer_size - rb->write_index > length) + { + /* there is enough space after write_index */ + rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, length); + rb->write_index += length; + } + else + { + rt_memcpy(&rb->buffer_ptr[rb->write_index], ptr, + rb->buffer_size - rb->write_index); + rt_memcpy(&rb->buffer_ptr[0], &ptr[rb->buffer_size - rb->write_index], + length - (rb->buffer_size - rb->write_index)); + rb->write_index = length - (rb->buffer_size - rb->write_index); + } + } + + return length; +} + +/** + * put a character into ring buffer + */ +rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer* rb, const rt_uint8_t ch) +{ + rt_uint16_t next; + + RT_ASSERT(rb != RT_NULL); + /* whether has enough space */ + next = rb->write_index + 1; + if (next >= rb->buffer_size) next = 0; + + if (next == rb->read_index) return 0; + + /* put character */ + rb->buffer_ptr[rb->write_index] = ch; + rb->write_index = next; + + return 1; +} + +/** + * 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 */ + if (rb->read_index > rb->write_index) + size = rb->buffer_size - rb->read_index + rb->write_index; + else + size = rb->write_index - rb->read_index; + + /* no data */ + if (size == 0) return 0; + + /* less data */ + if (size < length) length = size; + + if (rb->read_index > rb->write_index) + { + if (rb->buffer_size - rb->read_index > length) + { + /* copy directly */ + rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length); + rb->read_index += length; + } + else + { + /* copy first and second */ + rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], + rb->buffer_size - rb->read_index); + rt_memcpy(&ptr[rb->buffer_size - rb->read_index], &rb->buffer_ptr[0], + length - rb->buffer_size + rb->read_index); + rb->read_index = length - rb->buffer_size + rb->read_index; + } + } + else + { + rt_memcpy(ptr, &rb->buffer_ptr[rb->read_index], length); + rb->read_index += length; + } + + return length; +} + +/** + * get available data size + */ +rt_size_t rt_ringbuffer_available_size(struct rt_ringbuffer* rb) +{ + rt_size_t size; + + RT_ASSERT(rb != RT_NULL); + if (rb->read_index > rb->write_index) + size = rb->buffer_size - rb->read_index + rb->write_index; + else + size = rb->write_index - rb->read_index; + + /* return the available size */ + return size; +} + +/** + * get empty space size + */ +rt_size_t rt_ringbuffer_emptry_size(struct rt_ringbuffer* rb) +{ + RT_ASSERT(rb != RT_NULL); + + return rb->buffer_size - rt_ringbuffer_available_size(rb); +}