git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1501 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
gdisirio 2010-01-05 17:14:09 +00:00
parent de95f94fbe
commit 855fe2391d
15 changed files with 463 additions and 187 deletions

View File

@ -34,7 +34,7 @@
* ChibiOS/RT APIs are all named following this convention:
* @a ch\<group\>\<action\>\<suffix\>().
* The possible groups are: @a Sys, @a Sch, @a Time, @a VT, @a Thd, @a Sem,
* @a Mtx, @a Cond, @a Evt, @a Msg, @a IQ, @a OQ, @a IO, @a Dbg,
* @a Mtx, @a Cond, @a Evt, @a Msg, @a Stream, @a IO, @a IQ, @a OQ, @a Dbg,
* @a Core, @a Heap, @a Pool.
*
* @section api_suffixes API Names Suffixes

View File

@ -26,17 +26,17 @@
* - High Level Device Driver (<b>HLD</b>). This layer contains the definitions
* of the driver's APIs and the platform independent part of the driver.<br>
* An HLD is composed by two files:
* - @<driver@>.c, the high level implementation file. This file must be
* - @<driver@>.c, the HLD implementation file. This file must be
* included in the Makefile in order to use the driver.
* - @<driver@>.h, the high level header file. This file must be included
* by the application code in order to access the driver's APIs.
* - @<driver@>.h, the HLD header file. This file is implicitly
* included by the HAL header file @p hal.h.
* .
* - Low Level Device Driver (<b>LLD</b>). This layer contains the platform
* dependent part of the driver.<br>
* A LLD is composed by two files:
* - @<driver@>_lld.c, the low level implementation file. This file must be
* - @<driver@>_lld.c, the LLD implementation file. This file must be
* included in the Makefile in order to use the driver.
* - @<driver@>_lld.h, the high level header file. This file is implicitly
* - @<driver@>_lld.h, the LLD header file. This file is implicitly
* included by the HLD header file.
* .
* The LLD may be not present in those drivers that do not access the
@ -174,7 +174,7 @@
* @dot
digraph example {
rankdir="LR";
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"];
node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.8", height="0.8"];
edge [fontname=Helvetica, fontsize=8];
uninit [label="SPI_UNINIT", style="bold"];
stop [label="SPI_STOP\nLow Power"];

View File

@ -107,6 +107,10 @@ struct _serial_driver_methods {
* @brief @p SerialDriver virtual methods table.
*/
struct SerialDriverVMT {
/**
* @p BaseSequentialStream class inherited methods.
*/
struct _base_sequental_stream_methods bss;
/**
* @p BaseChannel class inherited methods.
*/
@ -133,6 +137,10 @@ struct _SerialDriver {
* Virtual Methods Table.
*/
const struct SerialDriverVMT *vmt;
/**
* @p BaseSequentialStream class inherited data.
*/
struct _base_sequental_stream_data bss;
/**
* @p BaseChannel class inherited data.
*/
@ -170,7 +178,7 @@ struct _SerialDriver {
#define sdGetWouldBlock(sdp) chIQIsEmpty(&(sdp)->sd.iqueue)
/**
* @brief Direct blocking write to a @p SerialDriver.
* @brief Direct write to a @p SerialDriver.
* @details This function bypasses the indirect access to the channel and
* writes directly on the output queue. This is faster but cannot
* be used to write to different channels implementations.
@ -179,8 +187,7 @@ struct _SerialDriver {
#define sdPut(sdp, b) chOQPut(&(sdp)->sd.oqueue, b)
/**
* @brief Direct blocking write on a @p SerialDriver with timeout
* specification.
* @brief Direct write to a @p SerialDriver with timeout specification.
* @details This function bypasses the indirect access to the channel and
* writes directly on the output queue. This is faster but cannot
* be used to write to different channels implementations.
@ -189,7 +196,7 @@ struct _SerialDriver {
#define sdPutTimeout(sdp, b, t) chOQPutTimeout(&(sdp)->sd.iqueue, b, t)
/**
* @brief Direct blocking read from a @p SerialDriver.
* @brief Direct read from a @p SerialDriver.
* @details This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
@ -198,8 +205,7 @@ struct _SerialDriver {
#define sdGet(sdp) chIQGet(&(sdp)->sd.iqueue)
/**
* @brief Direct blocking read from a @p SerialDriver with timeout
* specification.
* @brief Direct read from a @p SerialDriver with timeout specification.
* @details This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
@ -207,23 +213,78 @@ struct _SerialDriver {
*/
#define sdGetTimeout(sdp, t) chIQGetTimeout(&(sdp)->sd.iqueue, t)
/**
* @brief Direct blocking write to a @p SerialDriver.
* @details This function bypasses the indirect access to the channel and
* writes directly to the output queue. This is faster but cannot
* be used to write from different channels implementations.
* @see chIOWriteTimeout()
*/
#define sdWrite(sdp, b, n) \
chOQWriteTimeout(&(sdp)->sd.oqueue, b, n, TIME_INFINITE)
/**
* @brief Direct blocking write to a @p SerialDriver with timeout
* specification.
* @details This function bypasses the indirect access to the channel and
* writes directly to the output queue. This is faster but cannot
* be used to write from different channels implementations.
* @see chIOWriteTimeout()
*/
#define sdWriteTimeout(sdp, b, n, t) \
chOQWriteTimeout(&(sdp)->sd.oqueue, b, n, t)
/**
* @brief Direct non-blocking write to a @p SerialDriver.
* @details This function bypasses the indirect access to the channel and
* writes directly to the output queue. This is faster but cannot
* be used to write from different channels implementations.
* @see chIOWrite()
* @see chIOWriteTimeout()
*/
#define sdWrite(sdp, b, n) chOQWrite(&(sdp)->sd.oqueue, b, n)
#define sdAsynchronousWrite(sdp, b, n) \
chOQWriteTimeout(&(sdp)->sd.oqueue, b, n, TIME_IMMEDIATE)
/**
* @brief Direct non-blocking read on a @p SerialDriver.
* @brief Direct blocking read from a @p SerialDriver.
* @details This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
* @see chIORead()
* @see chIOReadTimeout()
*/
#define sdRead(sdp, b, n) chIQRead(&(sdp)->sd.iqueue, b, n)
#define sdRead(sdp, b, n) \
chIQReadTimeout(&(sdp)->sd.iqueue, b, n, TIME_INFINITE)
/**
* @brief Direct blocking read from a @p SerialDriver with timeout
* specification.
* @details This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
* @see chIOReadTimeout()
*/
#define sdReadTimeout(sdp, b, n, t) \
chIQReadTimeout(&(sdp)->sd.iqueue, b, n, t)
/**
* @brief Direct non-blocking read from a @p SerialDriver.
* @details This function bypasses the indirect access to the channel and
* reads directly from the input queue. This is faster but cannot
* be used to read from different channels implementations.
* @see chIOReadTimeout()
*/
#define sdAsynchronousRead(sdp, b, n) \
chIQReadTimeout(&(sdp)->sd.iqueue, b, n, TIME_IMMEDIATE)
/**
* @brief Returns the status change event source.
* @details The status change event source is broadcasted when the channel
* status is updated, the status flags can then be fetched and
* cheared by using @p sdGetAndClearFlags().
*
* @param[in] ip pointer to a @p SerialDriver object
* @return A pointer to an @p EventSource object.
*/
#define sdGetStatusChangeEventSource(ip) (&((ip)->vmt->sd.sevent))
/*===========================================================================*/
/* External declarations. */

View File

@ -45,6 +45,19 @@
* Interface implementation, the following functions just invoke the equivalent
* queue-level function or macro.
*/
static size_t writes(void *ip, const uint8_t *bp, size_t n) {
return chOQWriteTimeout(&((SerialDriver *)ip)->sd.oqueue, bp,
n, TIME_INFINITE);
}
static size_t reads(void *ip, uint8_t *bp, size_t n) {
return chIQReadTimeout(&((SerialDriver *)ip)->sd.iqueue, bp,
n, TIME_INFINITE);
}
static bool_t putwouldblock(void *ip) {
return chOQIsFull(&((SerialDriver *)ip)->sd.oqueue);
@ -55,29 +68,29 @@ static bool_t getwouldblock(void *ip) {
return chIQIsEmpty(&((SerialDriver *)ip)->sd.iqueue);
}
static msg_t put(void *ip, uint8_t b, systime_t timeout) {
static msg_t putt(void *ip, uint8_t b, systime_t timeout) {
return chOQPutTimeout(&((SerialDriver *)ip)->sd.oqueue, b, timeout);
}
static msg_t get(void *ip, systime_t timeout) {
static msg_t gett(void *ip, systime_t timeout) {
return chIQGetTimeout(&((SerialDriver *)ip)->sd.iqueue, timeout);
}
static size_t write(void *ip, uint8_t *buffer, size_t n) {
static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t time) {
return chOQWrite(&((SerialDriver *)ip)->sd.oqueue, buffer, n);
return chOQWriteTimeout(&((SerialDriver *)ip)->sd.oqueue, bp, n, time);
}
static size_t read(void *ip, uint8_t *buffer, size_t n) {
static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t time) {
return chIQRead(&((SerialDriver *)ip)->sd.iqueue, buffer, n);
return chIQReadTimeout(&((SerialDriver *)ip)->sd.iqueue, bp, n, time);
}
static const struct SerialDriverVMT vmt = {
{putwouldblock, getwouldblock, put, get},
{write, read},
{writes, reads},
{putwouldblock, getwouldblock, putt, gett, writet, readt},
{}
};
@ -112,10 +125,10 @@ void sdObjectInit(SerialDriver *sdp, qnotify_t inotify, qnotify_t onotify) {
chEvtInit(&sdp->bac.ievent);
chEvtInit(&sdp->bac.oevent);
chEvtInit(&sdp->sd.sevent);
sdp->sd.state = SD_STOP;
sdp->sd.flags = SD_NO_ERROR;
chIQInit(&sdp->sd.iqueue, sdp->sd.ib, SERIAL_BUFFERS_SIZE, inotify);
chOQInit(&sdp->sd.oqueue, sdp->sd.ob, SERIAL_BUFFERS_SIZE, onotify);
sdp->sd.state = SD_STOP;
}
/**

View File

@ -81,6 +81,7 @@
#include "threads.h"
#include "inline.h"
#include "queues.h"
#include "streams.h"
#include "channels.h"
#include "debug.h"

View File

@ -19,7 +19,7 @@
/**
* @file channels.h
* @brief I/O channels
* @brief I/O channels.
* @addtogroup io_channels
* @{
*/
@ -45,12 +45,22 @@ struct _base_channel_methods {
* @brief Channel put method with timeout specification.
* @see chIOPut()
*/
msg_t (*put)(void *instance, uint8_t b, systime_t timeout);
msg_t (*put)(void *instance, uint8_t b, systime_t time);
/**
* @brief Channel get method with timeout specification.
* @see chIOGet()
*/
msg_t (*get)(void *instance, systime_t timeout);
msg_t (*get)(void *instance, systime_t time);
/**
* @brief Channel write method with timeout specification.
* @see chIOWrite()
*/
size_t (*write)(void *instance, const uint8_t *bp, size_t n, systime_t time);
/**
* @brief Channel read method with timeout specification.
* @see chIORead()
*/
size_t (*read)(void *instance, uint8_t *bp, size_t n, systime_t time);
};
/**
@ -65,6 +75,10 @@ struct _base_channel_data {
* @brief @p BaseChannel virtual methods table.
*/
struct BaseChannelVMT {
/**
* @p BaseSequentialStream class inherited methods.
*/
struct _base_sequental_stream_methods bss;
/**
* @p BaseChannel class specific methods.
*/
@ -72,14 +86,21 @@ struct BaseChannelVMT {
};
/**
* @extends BaseSequentialStream
*
* @brief Base channel class.
* @details This class represents a generic, byte-wide, I/O channel.
* @details This class represents a generic, byte-wide, I/O channel. This class
* introduces generic I/O primitives with timeout specification.
*/
typedef struct {
/**
* Virtual Methods Table.
*/
const struct BaseChannelVMT *vmt;
/**
* @p BaseSequentialStream class inherited data.
*/
struct _base_sequental_stream_data bss;
/**
* @p BaseChannel class specific data.
*/
@ -88,7 +109,8 @@ typedef struct {
/**
* @brief Channel output check.
* @details This function verifies if a subsequent @p chIOPut() would block.
* @details This function verifies if a subsequent put/write operation would
* block.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @return The output queue status:
@ -100,7 +122,8 @@ typedef struct {
/**
* @brief Channel input check.
* @details This function verifies if a subsequent @p chIOGett() would block.
* @details This function verifies if a subsequent get/read operation would
* block.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @return The input queue status:
@ -130,7 +153,7 @@ typedef struct {
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] b the byte value to be written to the channel
* @param[in] timeout the number of ticks before the operation timeouts,
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
@ -140,7 +163,7 @@ typedef struct {
* @retval Q_TIMEOUT if the specified time expired.
* @retval Q_RESET if the channel associated queue (if any) was reset.
*/
#define chIOPutTimeout(ip, b, timeout) ((ip)->vmt->bc.put(ip, b, timeout))
#define chIOPutTimeout(ip, b, time) ((ip)->vmt->bc.put(ip, b, time))
/**
* @brief Channel blocking byte read.
@ -159,7 +182,7 @@ typedef struct {
* is not available then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] timeout the number of ticks before the operation timeouts,
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
@ -168,23 +191,49 @@ typedef struct {
* @retval Q_TIMEOUT if the specified time expired.
* @retval Q_RESET if the channel associated queue (if any) was reset.
*/
#define chIOGetTimeout(ip, timeout) ((ip)->vmt->bc.get(ip, timeout))
#define chIOGetTimeout(ip, time) ((ip)->vmt->bc.get(ip, time))
/**
* @brief Channel blocking write with timeout.
* @details The function writes data from a buffer to a channel. If the channel
* is not ready to accept data then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The number of bytes transferred.
*/
#define chIOWriteTimeout(ip, bp, n, time) \
((ip)->vmt->bac.write(ip, bp, n, time))
/**
* @brief Channel blocking read with timeout.
* @details The function reads data from a channel into a buffer. If the data
* is not available then the calling thread is suspended.
*
* @param[in] ip pointer to a @p BaseChannel or derived class
* @param[in] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The number of bytes transferred.
*/
#define chIOReadTimeout(ip, bp, n, time) \
((ip)->vmt->bac.read(ip, bp, n, time))
#if CH_USE_EVENTS
/**
* @brief @p BaseAsynchronousChannel specific methods.
*/
struct _base_asynchronous_channel_methods {
/**
* Channel asynchronous write method.
* @see chIOWrite()
*/
size_t (*write)(void *instance, uint8_t *buffer, size_t n);
/**
* Channel asynchronous read method.
* @see chIORead()
*/
size_t (*read)(void *instance, uint8_t *buffer, size_t n);
};
/**
@ -207,6 +256,10 @@ struct _base_asynchronous_channel_data {
* @brief @p BaseAsynchronousChannel virtual methods table.
*/
struct BaseAsynchronousChannelVMT {
/**
* @p BaseSequentialStream class inherited methods.
*/
struct _base_sequental_stream_methods bss;
/**
* @p BaseChannel class inherited methods.
*/
@ -221,14 +274,18 @@ struct BaseAsynchronousChannelVMT {
* @extends BaseChannel
*
* @brief Base asynchronous channel class.
* @details This class extends @p BaseChannel by adding methods for
* asynchronous I/O in an event-driven environment.
* @details This class extends @p BaseChannel by adding event sources fields
* for asynchronous I/O for use in an event-driven environment.
*/
typedef struct {
/**
* Virtual Methods Table.
*/
const struct BaseAsynchronousChannelVMT *vmt;
/**
* @p BaseSequentialStream class inherited data.
*/
struct _base_sequental_stream_data bss;
/**
* @p BaseChannel class inherited data.
*/
@ -239,32 +296,6 @@ typedef struct {
struct _base_asynchronous_channel_data bac;
} BaseAsynchronousChannel;
/**
* @brief Channel non-blocking write.
* @details The function writes data from a buffer to a channel. The
* transfer is non-blocking and can return zero if the channel is
* not read to accept data.
*
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived class
* @param[out] bp pointer to the buffer where the data is stored
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred.
*/
#define chIOWrite(ip, bp, n) ((ip)->vmt->bac.write(ip, bp, n))
/**
* @brief Channel non-blocking read.
* @details The function reads data from a channel into a buffer. The
* transfer is non-blocking and can return zero if the channel has
* no data immediately available.
*
* @param[in] ip pointer to a @p BaseAsynchronousChannel or derived class
* @param[out] bp pointer to the buffer where the input data is copied
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred.
*/
#define chIORead(ip, bp, n) ((ip)->vmt->bac.read(ip, bp, n))
/**
* @brief Returns the write event source.
* @details The write event source is broadcasted when the channel is ready

View File

@ -205,17 +205,19 @@ typedef GenericQueue OutputQueue;
#ifdef __cplusplus
extern "C" {
#endif
void chIQInit(InputQueue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
void chIQInit(InputQueue *qp, uint8_t *bp, size_t size, qnotify_t infy);
void chIQResetI(InputQueue *qp);
msg_t chIQPutI(InputQueue *qp, uint8_t b);
msg_t chIQGetTimeout(InputQueue *qp, systime_t timeout);
size_t chIQRead(InputQueue *qp, uint8_t *buffer, size_t n);
msg_t chIQGetTimeout(InputQueue *qp, systime_t time);
size_t chIQReadTimeout(InputQueue *qp, uint8_t *bp,
size_t n, systime_t time);
void chOQInit(OutputQueue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
void chOQInit(OutputQueue *queue, uint8_t *bp, size_t size, qnotify_t onfy);
void chOQResetI(OutputQueue *queue);
msg_t chOQPutTimeout(OutputQueue *queue, uint8_t b, systime_t timeout);
msg_t chOQPutTimeout(OutputQueue *queue, uint8_t b, systime_t time);
msg_t chOQGetI(OutputQueue *queue);
size_t chOQWrite(OutputQueue *queue, uint8_t *buffer, size_t n);
size_t chOQWriteTimeout(OutputQueue *queue, const uint8_t *bp,
size_t n, systime_t time);
#ifdef __cplusplus
}
#endif

106
os/kernel/include/streams.h Normal file
View File

@ -0,0 +1,106 @@
/*
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT 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 3 of the License, or
(at your option) any later version.
ChibiOS/RT 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, see <http://www.gnu.org/licenses/>.
*/
/**
* @file streams.h
* @brief Data streams.
* @addtogroup data_streams
* @{
*/
#ifndef _STREAMS_H_
#define _STREAMS_H_
/**
* @brief BaseSequentialStream specific methods.
*/
struct _base_sequental_stream_methods {
/**
* @brief Stream write buffer method.
*/
size_t (*write)(void *instance, const uint8_t *bp, size_t n);
/**
* @brief Stream read buffer method.
*/
size_t (*read)(void *instance, uint8_t *bp, size_t n);
};
/**
* @brief @p BaseSequentialStream specific data.
* @note It is empty because @p BaseSequentialStream is only an interface
* without implementation.
*/
struct _base_sequental_stream_data {
};
/**
* @brief @p BaseSequentialStream virtual methods table.
*/
struct BaseSequentialStreamVMT {
/**
* @p BaseSequentialStream class specific methods.
*/
struct _base_sequental_stream_methods bss;
};
/**
* @brief Base stream class.
* @details This class represents a generic blocking unbuffered sequential
* data stream.
*/
typedef struct {
/**
* Virtual Methods Table.
*/
const struct BaseSequentialStreamVMT *vmt;
/**
* @p BaseSequentialStream class specific data.
*/
struct _base_sequental_stream_data bss;
} BaseSequentialStream;
/**
* @brief Sequential Stream write.
* @details The function writes data from a buffer to a stream.
*
* @param[in] ip pointer to a @p BaseSequentialStream or derived class
* @param[in] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred. The return value can be less
* than the specified number of bytes if the stream reaches a
* physical end of file and cannot be extended.
*/
#define chSequentialStreamWrite(ip, bp, n) ((ip)->vmt->bss.write(ip, bp, n))
/**
* @brief Sequential Stream read.
* @details The function reads data from a stream into a buffer.
*
* @param[in] ip pointer to a @p BaseSequentialStream or derived class
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred. The return value can be less
* than the specified number of bytes if the stream reaches the end
* of the available data.
*/
#define chSequentialStreamRead(ip, bp, n) ((ip)->vmt->bss.read(ip, bp, n))
#endif /* _STREAMS_H_ */
/** @} */

View File

@ -282,18 +282,31 @@
* @ingroup kernel
*/
/**
* @defgroup data_streams Streams
* @brief Streams.
* @details This module define an abstract interface for generic data streams.
* Note that no code is present, streams are just abstract classes-like
* structures, you should look at the systems as to a set of abstract C++
* classes (even if written in C). This system has the advantage to make the
* access to streams independent from the implementation logic.<br>
* The stream interface can be used as base class for high level object types
* such as files, sockets, serial ports, pipes etc.
*
* @ingroup io_support
*/
/**
* @defgroup io_channels I/O Abstract Channels
* @brief Abstract I/O Channels.
* @details This module defines an abstract interface for I/O channels. Note
* that no code is present, I/O channels are just abstract classes-like
* structures, you should look at the systems as to a set of abstract C++
* classes (even if written in C). Specific device drivers can use/extend
* the interfaces and implement them.<br>
* @details This module defines an abstract interface for I/O channels by
* extending the @p BaseSequentialStream interface. Note that no code is
* present, I/O channels are just abstract classes-like structures,
* you should look at the systems as to a set of abstract C++ classes
* (even if written in C). Specific device drivers can use/extend the
* interface and implement them.<br>
* This system has the advantage to make the access to channels
* independent from the implementation logic. As example, an I/O channel
* interface can hide the access to a serial driver, to a networking socket
* and so on.
* independent from the implementation logic.
*
* @ingroup io_support
*/
@ -317,6 +330,8 @@
* .
* In order to use the I/O queues the @p CH_USE_QUEUES option must
* be specified in @p chconf.h.<br>
* I/O queues are usually used as an implementation layer for the I/O channels
* interface.
*
* @ingroup io_support
*/

View File

@ -34,33 +34,30 @@
* the bytes contained in the queue.
*
* @param[out] iqp pointer to an @p InputQueue structure
* @param[in] buffer pointer to a memory area allocated as queue buffer
* @param[in] bp pointer to a memory area allocated as queue buffer
* @param[in] size size of the queue buffer
* @param[in] inotify pointer to a callback function that is invoked when
* some data is read from the queue. The value can be
* @p NULL.
* @param[in] infy pointer to a callback function that is invoked when
* data is read from the queue. The value can be @p NULL.
*
* @note The callback is invoked from within the S-Locked system state,
* see @ref system_states.
*/
void chIQInit(InputQueue *iqp, uint8_t *buffer,
size_t size, qnotify_t inotify) {
void chIQInit(InputQueue *iqp, uint8_t *bp, size_t size, qnotify_t infy) {
iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = buffer;
iqp->q_top = buffer + size;
iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = bp;
iqp->q_top = bp + size;
iqp->q_notify = infy;
chSemInit(&iqp->q_sem, 0);
iqp->q_notify = inotify;
}
/**
* @brief Resets an input queue.
* @details All the data in the input queue is erased and lost, any waiting
* thread is resumed with status @p Q_RESET.
*
* @param[in] iqp pointer to an @p InputQueue structure
*
* @note A reset operation can be used by a low level driver in order to obtain
* immediate attention from the high level layers.
*
* @param[in] iqp pointer to an @p InputQueue structure
*/
void chIQResetI(InputQueue *iqp) {
@ -97,7 +94,7 @@ msg_t chIQPutI(InputQueue *iqp, uint8_t b) {
* in the queue or a timeout occurs.
*
* @param[in] iqp pointer to an @p InputQueue structure
* @param[in] timeout the number of ticks before the operation timeouts,
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
@ -106,12 +103,12 @@ msg_t chIQPutI(InputQueue *iqp, uint8_t b) {
* @retval Q_TIMEOUT if the specified time expired.
* @retval Q_RESET if the queue was reset.
*/
msg_t chIQGetTimeout(InputQueue *iqp, systime_t timeout) {
msg_t chIQGetTimeout(InputQueue *iqp, systime_t time) {
uint8_t b;
msg_t msg;
chSysLock();
if ((msg = chSemWaitTimeoutS(&iqp->q_sem, timeout)) < RDY_OK) {
if ((msg = chSemWaitTimeoutS(&iqp->q_sem, time)) < RDY_OK) {
chSysUnlock();
return msg;
}
@ -127,40 +124,45 @@ msg_t chIQGetTimeout(InputQueue *iqp, systime_t timeout) {
}
/**
* @brief Non-blocking read.
* @brief Input queue read with timeout.
* @details The function reads data from an input queue into a buffer. The
* transfer is non-blocking and can return zero if the queue is
* empty.
*
* @param[in] iqp pointer to an @p InputQueue structure
* @param[out] buffer pointer to the buffer where the input data is copied
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred.
*
* operation completes when the specified amount of data has been
* transferred or after the specified timeout or if the queue has
* been reset.
* @note The function is not atomic, if you need atomicity it is suggested
* to use a semaphore or a mutex for mutual exclusion.
* @note The queue callback is invoked one time <b>for each</b> byte removed
* from the queue.
*
* @param[in] iqp pointer to an @p InputQueue structure
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The number of bytes effectively transferred.
*/
size_t chIQRead(InputQueue *iqp, uint8_t *buffer, size_t n) {
size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp,
size_t n, systime_t time) {
qnotify_t nfy = iqp->q_notify;
size_t r = 0;
while (n--) {
do {
chSysLock();
if (chIQIsEmpty(iqp)) {
if (chSemWaitTimeoutS(&iqp->q_sem, time) != RDY_OK) {
chSysUnlock();
break;
return r;
}
chSemFastWaitI(&iqp->q_sem);
*buffer++ = *iqp->q_rdptr++;
*bp++ = *iqp->q_rdptr++;
if (iqp->q_rdptr >= iqp->q_top)
iqp->q_rdptr = iqp->q_buffer;
chSysUnlock();
if (nfy)
nfy();
chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
r++;
}
if (r && iqp->q_notify) {
chSysLock();
iqp->q_notify();
chSysUnlock();
}
} while (--n > 0);
return r;
}
@ -170,22 +172,20 @@ size_t chIQRead(InputQueue *iqp, uint8_t *buffer, size_t n) {
* the free bytes in the queue.
*
* @param[out] oqp pointer to an @p OutputQueue structure
* @param[in] buffer pointer to a memory area allocated as queue buffer
* @param[in] bp pointer to a memory area allocated as queue buffer
* @param[in] size size of the queue buffer
* @param[in] onotify pointer to a callback function that is invoked when
* some data is written to the queue. The value can be
* @p NULL.
* @param[in] onfy pointer to a callback function that is invoked when
* data is written to the queue. The value can be @p NULL.
*
* @note The callback is invoked from within the S-Locked system state,
* see @ref system_states.
*/
void chOQInit(OutputQueue *oqp, uint8_t *buffer,
size_t size, qnotify_t onotify) {
void chOQInit(OutputQueue *oqp, uint8_t *bp, size_t size, qnotify_t onfy) {
oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = buffer;
oqp->q_top = buffer + size;
oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = bp;
oqp->q_top = bp + size;
oqp->q_notify = onfy;
chSemInit(&oqp->q_sem, size);
oqp->q_notify = onotify;
}
/**
@ -212,7 +212,7 @@ void chOQResetI(OutputQueue *oqp) {
*
* @param[in] oqp pointer to an @p OutputQueue structure
* @param[in] b the byte value to be written in the queue
* @param[in] timeout the number of ticks before the operation timeouts,
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
@ -222,11 +222,11 @@ void chOQResetI(OutputQueue *oqp) {
* @retval Q_TIMEOUT if the specified time expired.
* @retval Q_RESET if the queue was reset.
*/
msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t timeout) {
msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t time) {
msg_t msg;
chSysLock();
if ((msg = chSemWaitTimeoutS(&oqp->q_sem, timeout)) < RDY_OK) {
if ((msg = chSemWaitTimeoutS(&oqp->q_sem, time)) < RDY_OK) {
chSysUnlock();
return msg;
}
@ -263,40 +263,45 @@ msg_t chOQGetI(OutputQueue *oqp) {
}
/**
* @brief Non-blocking write.
* @brief Output queue write with timeout.
* @details The function writes data from a buffer to an output queue. The
* transfer is non-blocking and can return zero if the queue is
* already full.
*
* @param[in] oqp pointer to an @p OutputQueue structure
* @param[out] buffer pointer to the buffer where the output data is stored
* @param[in] n the maximum amount of data to be transferred
* @return The number of bytes transferred.
*
* operation completes when the specified amount of data has been
* transferred or after the specified timeout or if the queue has
* been reset.
* @note The function is not atomic, if you need atomicity it is suggested
* to use a semaphore or a mutex for mutual exclusion.
* @note The queue callback is invoked one time <b>for each</b> byte inserted
* into the queue.
*
* @param[in] oqp pointer to an @p OutputQueue structure
* @param[out] bp pointer to the data buffer
* @param[in] n the maximum amount of data to be transferred
* @param[in] time the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_IMMEDIATE immediate timeout.
* - @a TIME_INFINITE no timeout.
* .
* @return The number of bytes effectively transferred.
*/
size_t chOQWrite(OutputQueue *oqp, uint8_t *buffer, size_t n) {
size_t chOQWriteTimeout(OutputQueue *oqp, const uint8_t *bp,
size_t n, systime_t time) {
qnotify_t nfy = oqp->q_notify;
size_t w = 0;
while (n--) {
do {
chSysLock();
if (chOQIsFull(oqp)) {
if (chSemWaitTimeoutS(&oqp->q_sem, time) != RDY_OK) {
chSysUnlock();
break;
return w;
}
chSemFastWaitI(&oqp->q_sem);
*oqp->q_wrptr++ = *buffer++;
*oqp->q_wrptr++ = *bp++;
if (oqp->q_wrptr >= oqp->q_top)
oqp->q_wrptr = oqp->q_buffer;
chSysUnlock();
if (nfy)
nfy();
chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
w++;
}
if (w && oqp->q_notify) {
chSysLock();
oqp->q_notify();
chSysUnlock();
}
} while (--n > 0);
return w;
}
#endif /* CH_USE_QUEUES */

View File

@ -78,9 +78,7 @@ int _read_r(struct _reent *r, int file, char * ptr, int len)
__errno_r(r) = EINVAL;
return -1;
}
*ptr++ = chIOGet(&STDOUT_SD);
if (--len > 0)
len = chIORead(&STDOUT_SD, (uint8_t *)ptr, (size_t)len);
len = sdRead(&STDOUT_SD, (uint8_t *)ptr, (size_t)len);
return len;
#else
(void)file;
@ -107,10 +105,6 @@ int _lseek_r(struct _reent *r, int file, int ptr, int dir)
int _write_r(struct _reent *r, int file, char * ptr, int len)
{
#if defined(STDOUT_SD)
int n;
#endif
(void)r;
(void)file;
(void)ptr;
@ -119,9 +113,7 @@ int _write_r(struct _reent *r, int file, char * ptr, int len)
__errno_r(r) = EINVAL;
return -1;
}
n = len;
while (n--)
chIOPut(&STDOUT_SD, *ptr++);
sdWrite(&STDOUT_SD, (uint8_t *)ptr, (size_t)len);
#endif
return len;
}

View File

@ -2,6 +2,21 @@
*** Releases ***
*****************************************************************************
*** 1.3.8 ***
- NEW: Introduced an abstract streams interface BaseSequentialStream.
- NEW: Added timeout specification to the I/O queues read/write primitives.
- CHANGE: Modified the BaseChannel interface in order to make it a
BaseSequentialStream descendant.
- CHANGE: Updated the serial driver model in order to expose the
BaseSequentialStream methods.
- CHANGE: The behavior of the read/write primitives is changed, now the
functions are synchronous and do not return until the specified number of
bytes have been transferred or a timeout occurs, the old behavior can be
replicated by specifying TIME_IMMEDIATE as timeout. Another difference is
that specifying zero as bytes number is like specifying the largest size_t
plus one, zero was an illegal value before.
- Documentation fixes and improvements, testing strategy explained.
*** 1.3.7 ***
- FIX: Fixed duplicated definition of SPI_USE_MUTUAL_EXCLUSION (bug 2922495).
- FIX: Fixed coverage tool hanging during execution (bug 2921120).

View File

@ -18,20 +18,52 @@
*/
/**
* @page testsuite Test Suite
* @page testsuite Testing Strategy
* <h2>Description</h2>
* Most of the ChibiOS/RT demos link a set of software modules (test suite) in
* order to verify the proper working of the kernel, the port and the demo
* itself.<br>
* Each Test Module performs a series of tests on a specified subsystem or
* itself.
*
* <h2>Strategy by Components</h2>
* The OS components are tested in various modes depending on their importance:
* - <b>Kernel</b>. The kernel code is subject to rigorous testing. The test
* suite aims to test <b>all</b> the kernel code and reach a code coverage
* as close to 100% as possible. In addition to the code coverage, the kernel
* code is tested for <b>functionality</b> and benchmarked for <b>speed</b>
* and <b>size</b> before each stable release. In addition to the code
* coverage and functional testing a <b>batch compilation test</b> is
* performed before each release, the kernel is compiled by alternatively
* enabling and disabling all the various configuration options, the
* kernel code is expected to compile without errors nor warnings and
* execute the test suite without failures (a specific simulator is used
* for this execution test, it is done automatically by a script because
* the entire sequence can require hours).<br>
* All the tests results are included as reports in the OS distribution
* under @p ./docs/reports.
* - <b>Ports</b>. The port code is tested by executing the kernel test
* suite on the target hardware. A port is validated only if it passes all
* the tests. Speed and size benchmarks for all the supported architectures
* are performed, both size and speed regressions are <b>monitored</b>.
* - <b>HAL</b>. The HAL high level code and device drivers implementations
* are tested by use in the various demos and/or by users.
* - <b>Various</b>. The miscellaneous code is tested by use in the various
* demos and/or by users.
* - <b>External Code</b>. Not tested, external libraries or components are
* used as-is or with minor patching where required, problems are usually
* reported upstream.
* .
* <h2>Kernel Test Suite</h2>
* The kernel test suite is divided in modules or test sequences. Each Test
* Module performs a series of tests on a specified kernel subsystem or
* subsystems and can report a failure/success status and/or a performance
* index as the test suite output.<br>
* The test suite is usually activated in the demo applications by pressing a
* button on the target board, see the readme into the various demos
* directories. The test suite output is usually sent through a serial port and
* can be examined by using a terminal emulator program.
* directories. The test suite output is usually sent through a serial port
* and can be examined by using a terminal emulator program.
*
* <h2>Kernel Test Modules</h2>
*
* <h2>Test Modules</h2>
* - @subpage test_threads
* - @subpage test_dynamic
* - @subpage test_msg

View File

@ -86,6 +86,7 @@ static void queues1_setup(void) {
static void queues1_execute(void) {
unsigned i;
size_t n;
/* Initial empty state */
test_assert(1, chIQIsEmpty(&iq), "not empty");
@ -107,9 +108,8 @@ static void queues1_execute(void) {
chIQPutI(&iq, 'A' + i);
/* Reading the whole thing */
test_assert(6,
chIQRead(&iq, wa[1], TEST_QUEUES_SIZE * 2) == TEST_QUEUES_SIZE,
"wrong returned size");
n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE);
test_assert(6, n == TEST_QUEUES_SIZE, "wrong returned size");
test_assert(7, chIQIsEmpty(&iq), "still full");
/* Testing reset */
@ -148,6 +148,7 @@ static void queues2_setup(void) {
static void queues2_execute(void) {
unsigned i;
size_t n;
/* Initial empty state */
test_assert(1, chOQIsEmpty(&oq), "not empty");
@ -165,9 +166,8 @@ static void queues2_execute(void) {
test_assert(5, chOQGetI(&oq) == Q_EMPTY, "failed to report Q_EMPTY");
/* Writing the whole thing */
test_assert(6,
chOQWrite(&oq, wa[1], TEST_QUEUES_SIZE * 2) == TEST_QUEUES_SIZE,
"wrong returned size");
n = chOQWriteTimeout(&oq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE);
test_assert(6, n == TEST_QUEUES_SIZE,"wrong returned size");
test_assert(7, chOQIsFull(&oq), "not full");
/* Testing reset */

View File

@ -5,6 +5,7 @@ X = In progress, some work done.
* = Done.
Before 1.4.0:
* Abstract streams interface (for MAC, USB endpoints, files, sockets etc).
* Abstract I/O channels rather than just serial ports.
* Add tests documentation to the general documentation via doxygen.
* Static object initializers.
@ -17,15 +18,16 @@ Before 1.4.0:
After 1.4.x
- I2C device driver class support.
- USB device support.
- Abstract streams interface (for MAC and USB endpoints).
- Remove any instance of unnamed structures/unions.
- MAC driver revision in order to support copy-less operations, this will
require changes to lwIP or a new TCP/IP stack however.
- Objects registry in the kernel.
- OSEK-style simple tasks within the idle thread.
- Code examples into the documentation.
- Update C++ wrapper (Heap, Pools, Mailboxes and any new feature).
- Threads Pools manager in the library.
? Minimal optional C-runtime library (complete enough for lwIP).
? Think to something for threads restart.
- Update C++ wrapper (Heap, Pools, Mailboxes and any new feature).
? Remove any instance of unnamed structures/unions.
Ideas for 2.x.x:
- High resolution timers and tickless kernel.
@ -40,7 +42,7 @@ Side projects:
* FatFS library integration and demo.
X ChibiOS Wizard, UML modeling and ChibiOS applications code and
documentation generator.
X OSEK layer.
? OSEK layer.
- Posix layer.
X File System
- Visual debugger/monitor interfaced through OpenOCD.
@ -48,3 +50,4 @@ X File System
Lower priority:
- More demos
- More ports
- More compilers.