diff options
-rw-r--r-- | docs/src/concepts.dox | 2 | ||||
-rw-r--r-- | os/hal/hal.dox | 12 | ||||
-rw-r--r-- | os/hal/include/serial.h | 83 | ||||
-rw-r--r-- | os/hal/src/serial.c | 31 | ||||
-rw-r--r-- | os/kernel/include/ch.h | 1 | ||||
-rw-r--r-- | os/kernel/include/channels.h | 127 | ||||
-rw-r--r-- | os/kernel/include/queues.h | 14 | ||||
-rw-r--r-- | os/kernel/include/streams.h | 106 | ||||
-rw-r--r-- | os/kernel/kernel.dox | 31 | ||||
-rw-r--r-- | os/kernel/src/chqueues.c | 145 | ||||
-rw-r--r-- | os/various/syscalls.c | 12 | ||||
-rw-r--r-- | readme.txt | 15 | ||||
-rw-r--r-- | test/test.dox | 44 | ||||
-rw-r--r-- | test/testqueues.c | 12 | ||||
-rw-r--r-- | todo.txt | 11 |
15 files changed, 461 insertions, 185 deletions
diff --git a/docs/src/concepts.dox b/docs/src/concepts.dox index bab26d064..d6364513b 100644 --- a/docs/src/concepts.dox +++ b/docs/src/concepts.dox @@ -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
diff --git a/os/hal/hal.dox b/os/hal/hal.dox index 81b5a148d..657185f8e 100644 --- a/os/hal/hal.dox +++ b/os/hal/hal.dox @@ -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"];
diff --git a/os/hal/include/serial.h b/os/hal/include/serial.h index c24ac3994..3f4a1a8ca 100644 --- a/os/hal/include/serial.h +++ b/os/hal/include/serial.h @@ -108,6 +108,10 @@ struct _serial_driver_methods { */
struct SerialDriverVMT {
/**
+ * @p BaseSequentialStream class inherited methods.
+ */
+ struct _base_sequental_stream_methods bss;
+ /**
* @p BaseChannel class inherited methods.
*/
struct _base_channel_methods bc;
@@ -134,6 +138,10 @@ struct _SerialDriver { */
const struct SerialDriverVMT *vmt;
/**
+ * @p BaseSequentialStream class inherited data.
+ */
+ struct _base_sequental_stream_data bss;
+ /**
* @p BaseChannel class inherited data.
*/
struct _base_channel_data bc;
@@ -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.
@@ -208,22 +214,77 @@ 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 chIOReadTimeout()
+ */
+#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 chIORead()
+ * @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 sdRead(sdp, b, n) chIQRead(&(sdp)->sd.iqueue, b, n)
+#define sdGetStatusChangeEventSource(ip) (&((ip)->vmt->sd.sevent))
/*===========================================================================*/
/* External declarations. */
diff --git a/os/hal/src/serial.c b/os/hal/src/serial.c index 4c2cb71c9..54db8e95d 100644 --- a/os/hal/src/serial.c +++ b/os/hal/src/serial.c @@ -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;
}
/**
diff --git a/os/kernel/include/ch.h b/os/kernel/include/ch.h index 5d15b13ae..ecac6f3f7 100644 --- a/os/kernel/include/ch.h +++ b/os/kernel/include/ch.h @@ -81,6 +81,7 @@ #include "threads.h"
#include "inline.h"
#include "queues.h"
+#include "streams.h"
#include "channels.h"
#include "debug.h"
diff --git a/os/kernel/include/channels.h b/os/kernel/include/channels.h index e9cc956a6..66f1d1168 100644 --- a/os/kernel/include/channels.h +++ b/os/kernel/include/channels.h @@ -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);
};
/**
@@ -66,14 +76,21 @@ struct _base_channel_data { */
struct BaseChannelVMT {
/**
+ * @p BaseSequentialStream class inherited methods.
+ */
+ struct _base_sequental_stream_methods bss;
+ /**
* @p BaseChannel class specific methods.
*/
struct _base_channel_methods bc;
};
/**
+ * @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 {
/**
@@ -81,6 +98,10 @@ typedef struct { */
const struct BaseChannelVMT *vmt;
/**
+ * @p BaseSequentialStream class inherited data.
+ */
+ struct _base_sequental_stream_data bss;
+ /**
* @p BaseChannel class specific data.
*/
struct _base_channel_data bc;
@@ -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);
};
/**
@@ -208,6 +257,10 @@ struct _base_asynchronous_channel_data { */
struct BaseAsynchronousChannelVMT {
/**
+ * @p BaseSequentialStream class inherited methods.
+ */
+ struct _base_sequental_stream_methods bss;
+ /**
* @p BaseChannel class inherited methods.
*/
struct _base_channel_methods bc;
@@ -221,8 +274,8 @@ 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 {
/**
@@ -230,6 +283,10 @@ typedef struct { */
const struct BaseAsynchronousChannelVMT *vmt;
/**
+ * @p BaseSequentialStream class inherited data.
+ */
+ struct _base_sequental_stream_data bss;
+ /**
* @p BaseChannel class inherited data.
*/
struct _base_channel_data bc;
@@ -240,32 +297,6 @@ typedef struct { } 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
* for write operations. This usually happens when the internal
diff --git a/os/kernel/include/queues.h b/os/kernel/include/queues.h index 25ba82d65..93a2ab7b2 100644 --- a/os/kernel/include/queues.h +++ b/os/kernel/include/queues.h @@ -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 diff --git a/os/kernel/include/streams.h b/os/kernel/include/streams.h new file mode 100644 index 000000000..f01d0999b --- /dev/null +++ b/os/kernel/include/streams.h @@ -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_ */
+
+/** @} */
diff --git a/os/kernel/kernel.dox b/os/kernel/kernel.dox index 0f544d04e..072be41ec 100644 --- a/os/kernel/kernel.dox +++ b/os/kernel/kernel.dox @@ -283,17 +283,30 @@ */
/**
+ * @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
*/
diff --git a/os/kernel/src/chqueues.c b/os/kernel/src/chqueues.c index a346ee07f..f4111a814 100644 --- a/os/kernel/src/chqueues.c +++ b/os/kernel/src/chqueues.c @@ -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.
+ * 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] buffer pointer to the buffer where the input data is copied
+ * @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.
- *
- * @note The function is not atomic, if you need atomicity it is suggested
- * to use a semaphore or a mutex for mutual exclusion.
+ * @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.
+ * 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] buffer pointer to the buffer where the output data is stored
+ * @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.
- *
- * @note The function is not atomic, if you need atomicity it is suggested
- * to use a semaphore or a mutex for mutual exclusion.
+ * @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 */
diff --git a/os/various/syscalls.c b/os/various/syscalls.c index abce2eea8..5c886f8f5 100644 --- a/os/various/syscalls.c +++ b/os/various/syscalls.c @@ -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; } diff --git a/readme.txt b/readme.txt index 8ebbc732f..66fc27088 100644 --- a/readme.txt +++ b/readme.txt @@ -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).
diff --git a/test/test.dox b/test/test.dox index ad3c03927..75a46366e 100644 --- a/test/test.dox +++ b/test/test.dox @@ -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
diff --git a/test/testqueues.c b/test/testqueues.c index 6989442c4..c07e8aee3 100644 --- a/test/testqueues.c +++ b/test/testqueues.c @@ -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 */
@@ -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.
|