I/O queues improvements, removed half duplex queues.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@926 35acf78f-673a-0410-8e92-d51de3d6d3f4master
parent
e0073441fe
commit
46e56d7349
|
@ -82,6 +82,13 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
|
||||||
real context switch time, previous benchmarks introduced too much overhead
|
real context switch time, previous benchmarks introduced too much overhead
|
||||||
to the measurement. The STM32 performs the context switch in under 1.48uS.
|
to the measurement. The STM32 performs the context switch in under 1.48uS.
|
||||||
- NEW: Added architecture name strings to the port code.
|
- NEW: Added architecture name strings to the port code.
|
||||||
|
- NEW: The I/O queues code was improved, now there are 2 separate structures:
|
||||||
|
InputQueue and Output queues. There are some changes int the queue APIs
|
||||||
|
in order to make them more symmetrical and functional. Improved the queues
|
||||||
|
documentation.
|
||||||
|
- CHANGE: Removed the half duplex queues and half duplex serial drivers because
|
||||||
|
it was never extensively tested. The code is still available but not as part
|
||||||
|
of the kernel.
|
||||||
- CHANGE: Removed the chMsgSendWithEvent() function. It is rarely used and
|
- CHANGE: Removed the chMsgSendWithEvent() function. It is rarely used and
|
||||||
the functionality can be re-created with a compound atomic operation. Also
|
the functionality can be re-created with a compound atomic operation. Also
|
||||||
removed the CH_USE_MESSAGES_EVENT configuration option.
|
removed the CH_USE_MESSAGES_EVENT configuration option.
|
||||||
|
|
536
src/chqueues.c
536
src/chqueues.c
|
@ -33,250 +33,259 @@
|
||||||
* @details A Semaphore is internally initialized and works as a counter of
|
* @details A Semaphore is internally initialized and works as a counter of
|
||||||
* the bytes contained in the queue.
|
* the bytes contained in the queue.
|
||||||
*
|
*
|
||||||
* @param[out] qp pointer to a @p Queue structure
|
* @param[out] iqp pointer to an @p InputQueue structure
|
||||||
* @param[in] buffer pointer to a memory area allocated as queue buffer
|
* @param[in] buffer pointer to a memory area allocated as queue buffer
|
||||||
* @param[in] size size of the queue buffer
|
* @param[in] size size of the queue buffer
|
||||||
* @param[in] inotify pointer to a callback function that is invoked when
|
* @param[in] inotify pointer to a callback function that is invoked when
|
||||||
* some data is read from the Queue. The value can be
|
* some data is read from the queue. The value can be
|
||||||
* @p NULL.
|
* @p NULL.
|
||||||
|
*
|
||||||
|
* @note The callback is invoked from within the S-Locked system state,
|
||||||
|
* see @ref system_states.
|
||||||
*/
|
*/
|
||||||
void chIQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t inotify) {
|
void chIQInit(InputQueue *iqp, uint8_t *buffer,
|
||||||
|
size_t size, qnotify_t inotify) {
|
||||||
|
|
||||||
qp->q_buffer = qp->q_rdptr = qp->q_wrptr = buffer;
|
iqp->q_buffer = iqp->q_rdptr = iqp->q_wrptr = buffer;
|
||||||
qp->q_top = buffer + size;
|
iqp->q_top = buffer + size;
|
||||||
chSemInit(&qp->q_sem, 0);
|
chSemInit(&iqp->q_sem, 0);
|
||||||
qp->q_notify = inotify;
|
iqp->q_notify = inotify;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Resets an input queue.
|
* @brief Resets an input queue.
|
||||||
* @details All the data is lost and the waiting threads resumed.
|
* @details All the data in the input queue is erased and lost, any waiting
|
||||||
|
* thread is resumed with status @p Q_RESET.
|
||||||
*
|
*
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
* @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.
|
||||||
*/
|
*/
|
||||||
void chIQReset(Queue *qp) {
|
void chIQResetI(InputQueue *iqp) {
|
||||||
|
|
||||||
chSysLock();
|
iqp->q_rdptr = iqp->q_wrptr = iqp->q_buffer;
|
||||||
|
chSemResetI(&iqp->q_sem, 0);
|
||||||
qp->q_rdptr = qp->q_wrptr = qp->q_buffer;
|
|
||||||
chSemResetI(&qp->q_sem, 0);
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inserts a byte into an input queue.
|
* @brief Input queue write.
|
||||||
|
* @details A byte value is written into the low end of an input queue.
|
||||||
*
|
*
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
* @param[in] b the byte value to be written
|
* @param[in] b the byte value to be written in the queue
|
||||||
* @retval Q_OK if the operation is successful.
|
* @return The operation status, it can be one of:
|
||||||
* @retval Q_FULL if the queue is full.
|
* @retval Q_OK if the operation has been completed with success.
|
||||||
* @note This function is the lower side endpoint of the Input Queue.
|
* @retval Q_FULL if the queue is full and the operation cannot be completed.
|
||||||
* @note This function must be called with interrupts disabled or from an
|
|
||||||
* interrupt handler.
|
|
||||||
*/
|
*/
|
||||||
msg_t chIQPutI(Queue *qp, uint8_t b) {
|
msg_t chIQPutI(InputQueue *iqp, uint8_t b) {
|
||||||
|
|
||||||
if (chIQIsFull(qp))
|
if (chIQIsFull(iqp))
|
||||||
return Q_FULL;
|
return Q_FULL;
|
||||||
|
|
||||||
*qp->q_wrptr++ = b;
|
*iqp->q_wrptr++ = b;
|
||||||
if (qp->q_wrptr >= qp->q_top)
|
if (iqp->q_wrptr >= iqp->q_top)
|
||||||
qp->q_wrptr = qp->q_buffer;
|
iqp->q_wrptr = iqp->q_buffer;
|
||||||
chSemSignalI(&qp->q_sem);
|
chSemSignalI(&iqp->q_sem);
|
||||||
return Q_OK;
|
return Q_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets a byte from the input queue.
|
* @brief Input queue read.
|
||||||
* @details If the queue is empty then the calling thread is suspended until
|
* @details This function reads a byte value from an input queue. If the queue
|
||||||
* a byte arrives in the queue.
|
* is empty then the calling thread is suspended until a byte arrives
|
||||||
|
* in the queue or a timeout occurs.
|
||||||
*
|
*
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
* @return A byte value from the queue.
|
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||||
* @retval Q_RESET if the queue was reset.
|
* the following special values are allowed:
|
||||||
*/
|
* - @a TIME_IMMEDIATE immediate timeout.
|
||||||
msg_t chIQGet(Queue *qp) {
|
* - @a TIME_INFINITE no timeout.
|
||||||
uint8_t b;
|
* .
|
||||||
|
* @return A byte value from the queue or:
|
||||||
chSysLock();
|
|
||||||
|
|
||||||
if (chSemWaitS(&qp->q_sem) < RDY_OK) {
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
return Q_RESET;
|
|
||||||
}
|
|
||||||
b = *qp->q_rdptr++;
|
|
||||||
if (qp->q_rdptr >= qp->q_top)
|
|
||||||
qp->q_rdptr = qp->q_buffer;
|
|
||||||
|
|
||||||
if (qp->q_notify)
|
|
||||||
qp->q_notify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CH_USE_QUEUES_TIMEOUT && CH_USE_SEMAPHORES_TIMEOUT
|
|
||||||
/**
|
|
||||||
* @brief Gets a byte from the input queue.
|
|
||||||
* @details If the queue is empty then the calling thread is suspended until
|
|
||||||
* a byte arrives in the queue or the specified time expires.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
|
||||||
* @param[in] time the number of ticks before the operation timeouts
|
|
||||||
* @return A byte value from the queue.
|
|
||||||
* @retval Q_TIMEOUT if the specified time expired.
|
* @retval Q_TIMEOUT if the specified time expired.
|
||||||
* @retval Q_RESET if the queue was reset.
|
* @retval Q_RESET if the queue was reset.
|
||||||
* @note The function is available only if the @p CH_USE_QUEUES_TIMEOUT and
|
*
|
||||||
* @p CH_USE_SEMAPHORES_TIMEOUT options are enabled in @p chconf.h.
|
* @note The @p time parameter is only meaningful if the
|
||||||
|
* @p CH_USE_SEMAPHORES_TIMEOUT kernel option is activated,
|
||||||
|
* otherwise only the @p TIME_INFINITE value is accepted.
|
||||||
*/
|
*/
|
||||||
msg_t chIQGetTimeout(Queue *qp, systime_t time) {
|
msg_t chIQGetTimeout(InputQueue *iqp, systime_t timeout) {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
msg_t msg;
|
msg_t msg;
|
||||||
|
|
||||||
|
#if CH_USE_SEMAPHORES_TIMEOUT
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
if ((msg = chSemWaitTimeoutS(&iqp->q_sem, timeout)) < RDY_OK) {
|
||||||
if ((msg = chSemWaitTimeoutS(&qp->q_sem, time)) < RDY_OK) {
|
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
b = *qp->q_rdptr++;
|
#else
|
||||||
if (qp->q_rdptr >= qp->q_top)
|
chDbgCheck(timeout == TIME_INFINITE, "chIQGetTimeout");
|
||||||
qp->q_rdptr = qp->q_buffer;
|
|
||||||
|
|
||||||
if (qp->q_notify)
|
chSysLock();
|
||||||
qp->q_notify();
|
if ((msg = chSemWaitS(&iqp->q_sem)) < RDY_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
b = *iqp->q_rdptr++;
|
||||||
|
if (iqp->q_rdptr >= iqp->q_top)
|
||||||
|
iqp->q_rdptr = iqp->q_buffer;
|
||||||
|
|
||||||
|
if (iqp->q_notify)
|
||||||
|
iqp->q_notify();
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
#endif /* (CH_USE_QUEUES_TIMEOUT && CH_USE_SEMAPHORES_TIMEOUT */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reads some data from the input queue into the specified buffer.
|
* @brief Non-blocking read.
|
||||||
* @details The function is non-blocking and can return zero if the queue is
|
* @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.
|
* empty.
|
||||||
*
|
*
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
* @param[out] buffer the data buffer
|
* @param[out] buffer pointer to the buffer where the input data is copied
|
||||||
* @param[in] n the maximum amount of data to be read
|
* @param[in] n the maximum amount of data to be transferred
|
||||||
* @return The number of bytes read.
|
* @return The number of bytes transferred.
|
||||||
* @note This function is the upper side endpoint of the input queue.
|
*
|
||||||
* @note The function is not atomic, if you need atomicity it is suggested
|
* @note The function is not atomic, if you need atomicity it is suggested
|
||||||
* to use a semaphore for mutual exclusion.
|
* to use a semaphore or a mutex for mutual exclusion.
|
||||||
*/
|
*/
|
||||||
size_t chIQRead(Queue *qp, uint8_t *buffer, size_t n) {
|
size_t chIQRead(InputQueue *iqp, uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
size_t r = 0;
|
size_t r = 0;
|
||||||
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
if (chIQIsEmpty(iqp)) {
|
||||||
if (chIQIsEmpty(qp)) {
|
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
chSemFastWaitI(&qp->q_sem);
|
chSemFastWaitI(&iqp->q_sem);
|
||||||
*buffer++ = *qp->q_rdptr++;
|
*buffer++ = *iqp->q_rdptr++;
|
||||||
if (qp->q_rdptr >= qp->q_top)
|
if (iqp->q_rdptr >= iqp->q_top)
|
||||||
qp->q_rdptr = qp->q_buffer;
|
iqp->q_rdptr = iqp->q_buffer;
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
|
if (r && iqp->q_notify) {
|
||||||
if (r && qp->q_notify) {
|
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
iqp->q_notify();
|
||||||
qp->q_notify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes an output queue.
|
* @brief Initializes an output queue.
|
||||||
* @details A Semaphore is internally initialized and works as a counter of the
|
* @details A Semaphore is internally initialized and works as a counter of
|
||||||
* free bytes in the queue.
|
* the free bytes in the queue.
|
||||||
*
|
*
|
||||||
* @param[out] qp pointer to a @p Queue structure
|
* @param[out] oqp pointer to an @p OutputQueue structure
|
||||||
* @param[in] buffer pointer to a memory area allocated as queue buffer
|
* @param[in] buffer pointer to a memory area allocated as queue buffer
|
||||||
* @param[in] size size of the queue buffer
|
* @param[in] size size of the queue buffer
|
||||||
* @param[in] onotify pointer to a callback function that is invoked when
|
* @param[in] onotify pointer to a callback function that is invoked when
|
||||||
* some data is written in the Queue. The value can be
|
* some data is written to the queue. The value can be
|
||||||
* @p NULL.
|
* @p NULL.
|
||||||
|
*
|
||||||
|
* @note The callback is invoked from within the S-Locked system state,
|
||||||
|
* see @ref system_states.
|
||||||
*/
|
*/
|
||||||
void chOQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t onotify) {
|
void chOQInit(OutputQueue *oqp, uint8_t *buffer,
|
||||||
|
size_t size, qnotify_t onotify) {
|
||||||
|
|
||||||
qp->q_buffer = qp->q_rdptr = qp->q_wrptr = buffer;
|
oqp->q_buffer = oqp->q_rdptr = oqp->q_wrptr = buffer;
|
||||||
qp->q_top = buffer + size;
|
oqp->q_top = buffer + size;
|
||||||
chSemInit(&qp->q_sem, size);
|
chSemInit(&oqp->q_sem, size);
|
||||||
qp->q_notify = onotify;
|
oqp->q_notify = onotify;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Resets an Output Queue.
|
* @brief Resets an output queue.
|
||||||
* @details All the data is lost and the waiting threads resumed.
|
* @details All the data in the output queue is erased and lost, any waiting
|
||||||
|
* thread is resumed with status @p Q_RESET.
|
||||||
*
|
*
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
*
|
||||||
|
* @note A reset operation can be used by a low level driver in order to obtain
|
||||||
|
* immediate attention from the high level layers.
|
||||||
*/
|
*/
|
||||||
void chOQReset(Queue *qp) {
|
void chOQResetI(OutputQueue *oqp) {
|
||||||
|
|
||||||
|
oqp->q_rdptr = oqp->q_wrptr = oqp->q_buffer;
|
||||||
|
chSemResetI(&oqp->q_sem, (cnt_t)(oqp->q_top - oqp->q_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue write.
|
||||||
|
* @details This function writes a byte value to an output queue. If the queue
|
||||||
|
* is full then the calling thread is suspended until there is space
|
||||||
|
* in the queue or a timeout occurs.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @param[in] timeout 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 operation status:
|
||||||
|
* @retval Q_OK if the operation succeeded.
|
||||||
|
* @retval Q_TIMEOUT if the specified time expired.
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*
|
||||||
|
* @note The @p time parameter is only meaningful if the
|
||||||
|
* @p CH_USE_SEMAPHORES_TIMEOUT kernel option is activated,
|
||||||
|
* otherwise only the @p TIME_INFINITE value is accepted.
|
||||||
|
*/
|
||||||
|
msg_t chOQPutTimeout(OutputQueue *oqp, uint8_t b, systime_t timeout) {
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
#if CH_USE_SEMAPHORES_TIMEOUT
|
||||||
|
chSysLock();
|
||||||
|
if ((msg = chSemWaitTimeoutS(&oqp->q_sem, timeout)) < RDY_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
chDbgCheck(timeout == TIME_INFINITE, "chOQPutTimeout");
|
||||||
|
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
if ((msg = chSemWaitS(&oqp->q_sem)) < RDY_OK) {
|
||||||
|
chSysUnlock();
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*oqp->q_wrptr++ = b;
|
||||||
|
if (oqp->q_wrptr >= oqp->q_top)
|
||||||
|
oqp->q_wrptr = oqp->q_buffer;
|
||||||
|
|
||||||
qp->q_rdptr = qp->q_wrptr = qp->q_buffer;
|
if (oqp->q_notify)
|
||||||
chSemResetI(&qp->q_sem, (cnt_t)(qp->q_top - qp->q_buffer));
|
oqp->q_notify();
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
|
return Q_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inserts a byte in the output queue.
|
* @brief Output queue read.
|
||||||
* @details If the queue is full then the thread is suspended until the queue
|
* @details A byte value is read from the low end of an output queue.
|
||||||
* has free space available.
|
|
||||||
*
|
*
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
* @param[in] b the byte value to be written
|
* @return The byte value from the queue or:
|
||||||
*/
|
|
||||||
void chOQPut(Queue *qp, uint8_t b) {
|
|
||||||
|
|
||||||
chSysLock();
|
|
||||||
|
|
||||||
chSemWaitS(&qp->q_sem);
|
|
||||||
*qp->q_wrptr++ = b;
|
|
||||||
if (qp->q_wrptr >= qp->q_top)
|
|
||||||
qp->q_wrptr = qp->q_buffer;
|
|
||||||
|
|
||||||
if (qp->q_notify)
|
|
||||||
qp->q_notify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets a byte from an output queue.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p Queue structure
|
|
||||||
* @return The byte value from the queue.
|
|
||||||
* @retval Q_EMPTY if the queue is empty.
|
* @retval Q_EMPTY if the queue is empty.
|
||||||
* @note This function is the lower side endpoint of the output queue.
|
|
||||||
* @note This function must be called with interrupts disabled or from an
|
|
||||||
* interrupt handler.
|
|
||||||
*/
|
*/
|
||||||
msg_t chOQGetI(Queue *qp) {
|
msg_t chOQGetI(OutputQueue *oqp) {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
|
|
||||||
if (chOQIsEmpty(qp))
|
if (chOQIsEmpty(oqp))
|
||||||
return Q_EMPTY;
|
return Q_EMPTY;
|
||||||
|
|
||||||
b = *qp->q_rdptr++;
|
b = *oqp->q_rdptr++;
|
||||||
if (qp->q_rdptr >= qp->q_top)
|
if (oqp->q_rdptr >= oqp->q_top)
|
||||||
qp->q_rdptr = qp->q_buffer;
|
oqp->q_rdptr = oqp->q_buffer;
|
||||||
chSemSignalI(&qp->q_sem);
|
chSemSignalI(&oqp->q_sem);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,218 +302,43 @@ msg_t chOQGetI(Queue *qp) {
|
||||||
* @note The function is not atomic, if you need atomicity it is suggested
|
* @note The function is not atomic, if you need atomicity it is suggested
|
||||||
* to use a semaphore for mutual exclusion.
|
* to use a semaphore for mutual exclusion.
|
||||||
*/
|
*/
|
||||||
size_t chOQWrite(Queue *qp, uint8_t *buffer, size_t n) {
|
/**
|
||||||
|
* @brief Non-blocking write.
|
||||||
|
* @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.
|
||||||
|
*
|
||||||
|
* @note The function is not atomic, if you need atomicity it is suggested
|
||||||
|
* to use a semaphore or a mutex for mutual exclusion.
|
||||||
|
*/
|
||||||
|
size_t chOQWrite(OutputQueue *oqp, uint8_t *buffer, size_t n) {
|
||||||
|
|
||||||
size_t w = 0;
|
size_t w = 0;
|
||||||
while (n--) {
|
while (n--) {
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
if (chOQIsFull(oqp)) {
|
||||||
if (chOQIsFull(qp)) {
|
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
chSemFastWaitI(&qp->q_sem);
|
chSemFastWaitI(&oqp->q_sem);
|
||||||
*qp->q_wrptr++ = *buffer++;
|
*oqp->q_wrptr++ = *buffer++;
|
||||||
if (qp->q_wrptr >= qp->q_top)
|
if (oqp->q_wrptr >= oqp->q_top)
|
||||||
qp->q_wrptr = qp->q_buffer;
|
oqp->q_wrptr = oqp->q_buffer;
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
w++;
|
w++;
|
||||||
}
|
}
|
||||||
|
if (w && oqp->q_notify) {
|
||||||
if (w && qp->q_notify) {
|
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
oqp->q_notify();
|
||||||
qp->q_notify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
#endif /* CH_USE_QUEUES */
|
#endif /* CH_USE_QUEUES */
|
||||||
|
|
||||||
#if CH_USE_QUEUES_HALFDUPLEX
|
|
||||||
/**
|
|
||||||
* @brief Initializes an half duplex queue.
|
|
||||||
*
|
|
||||||
* @param[out] qp pointer to the @p HalfDuplexQueue structure
|
|
||||||
* @param[in] buffer pointer to a memory area allocated as buffer for the queue
|
|
||||||
* @param[in] size the 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] onotify pointer to a callback function that is invoked when
|
|
||||||
* some data is written to the queue. The value can be
|
|
||||||
* @p NULL.
|
|
||||||
*/
|
|
||||||
void chHDQInit(HalfDuplexQueue *qp, uint8_t *buffer, size_t size,
|
|
||||||
qnotify_t inotify, qnotify_t onotify) {
|
|
||||||
|
|
||||||
qp->hdq_buffer = qp->hdq_rdptr = qp->hdq_wrptr = buffer;
|
|
||||||
qp->hdq_top = buffer + size;
|
|
||||||
chSemInit(&qp->hdq_isem, 0);
|
|
||||||
chSemInit(&qp->hdq_osem, size);
|
|
||||||
qp->hdq_inotify = inotify;
|
|
||||||
qp->hdq_onotify = onotify;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reads a byte from the receive queue.
|
|
||||||
* @details If the queue is empty or is in transmission mode then the invoking
|
|
||||||
* thread is suspended.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p HalfDuplexQueue structure
|
|
||||||
* @return The byte value.
|
|
||||||
* @retval Q_RESET if the queue was reset.
|
|
||||||
*/
|
|
||||||
msg_t chHDQGetReceive(HalfDuplexQueue *qp) {
|
|
||||||
uint8_t b;
|
|
||||||
|
|
||||||
chSysLock();
|
|
||||||
|
|
||||||
if (chSemWaitS(&qp->hdq_isem) < RDY_OK) {
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
return Q_RESET;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* NOTE: The semaphore can be signaled only if the queue is in
|
|
||||||
* receive mode.
|
|
||||||
*/
|
|
||||||
b = *qp->hdq_rdptr++;
|
|
||||||
if (qp->hdq_rdptr >= qp->hdq_top)
|
|
||||||
qp->hdq_rdptr = qp->hdq_buffer;
|
|
||||||
|
|
||||||
if (qp->hdq_inotify)
|
|
||||||
qp->hdq_inotify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CH_USE_QUEUES_TIMEOUT && CH_USE_SEMAPHORES_TIMEOUT
|
|
||||||
/**
|
|
||||||
* @brief Reads a byte from the receive queue.
|
|
||||||
* @details If the queue is empty or is in transmission mode then the invoking
|
|
||||||
* thread is suspended.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p HalfDuplexQueue structure
|
|
||||||
* @param[in] time the number of ticks before the operation timouts
|
|
||||||
* @return The byte value.
|
|
||||||
* @retval Q_TIMEOUT if a timeout occurs.
|
|
||||||
* @note The function is available only if the @p CH_USE_QUEUES_TIMEOUT and
|
|
||||||
* @p CH_USE_SEMAPHORES_TIMEOUT options are enabled in @p chconf.h.
|
|
||||||
*/
|
|
||||||
msg_t chHDQGetReceiveTimeout(HalfDuplexQueue *qp, systime_t time) {
|
|
||||||
uint8_t b;
|
|
||||||
msg_t msg;
|
|
||||||
|
|
||||||
chSysLock();
|
|
||||||
|
|
||||||
if ((msg = chSemWaitTimeoutS(&qp->hdq_isem, time)) < RDY_OK) {
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* NOTE: The semaphore can be signaled only if the queue is in
|
|
||||||
* receive mode.
|
|
||||||
*/
|
|
||||||
b = *qp->hdq_rdptr++;
|
|
||||||
if (qp->hdq_rdptr >= qp->hdq_top)
|
|
||||||
qp->hdq_rdptr = qp->hdq_buffer;
|
|
||||||
|
|
||||||
if (qp->hdq_inotify)
|
|
||||||
qp->hdq_inotify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
#endif /* CH_USE_QUEUES_TIMEOUT && CH_USE_SEMAPHORES_TIMEOUT */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Writes a byte into the transmit queue.
|
|
||||||
* @details If the buffer contains unread input data then the the buffer is
|
|
||||||
* cleared and the queue goes in transmission mode.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p HalfDuplexQueue structure
|
|
||||||
* @param[in] b the byte value to be written
|
|
||||||
*/
|
|
||||||
void chHDQPutTransmit(HalfDuplexQueue *qp, uint8_t b) {
|
|
||||||
|
|
||||||
chSysLock();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Transmission mode requires that all the unread data must be destroyed.
|
|
||||||
*/
|
|
||||||
if (qp->hdq_isem.s_cnt > 0) {
|
|
||||||
qp->hdq_isem.s_cnt = 0;
|
|
||||||
qp->hdq_rdptr = qp->hdq_wrptr = qp->hdq_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Goes in transmission mode.
|
|
||||||
*/
|
|
||||||
chSemWaitS(&qp->hdq_osem);
|
|
||||||
*qp->hdq_wrptr++ = b;
|
|
||||||
if (qp->hdq_wrptr >= qp->hdq_top)
|
|
||||||
qp->hdq_wrptr = qp->hdq_buffer;
|
|
||||||
|
|
||||||
if (qp->hdq_onotify)
|
|
||||||
qp->hdq_onotify();
|
|
||||||
|
|
||||||
chSysUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets a byte from the transmit queue.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p HalfDuplexQueue structure
|
|
||||||
* @return The byte value.
|
|
||||||
* @retval Q_EMPTY if the transmit queue is empty (not in transmission mode).
|
|
||||||
* @note This function must be called with interrupts disabled or from an
|
|
||||||
* interrupt handler.
|
|
||||||
*/
|
|
||||||
msg_t chHDQGetTransmitI(HalfDuplexQueue *qp) {
|
|
||||||
uint8_t b;
|
|
||||||
|
|
||||||
if (!chHDQIsTransmitting(qp))
|
|
||||||
return Q_EMPTY;
|
|
||||||
|
|
||||||
b = *qp->hdq_rdptr++;
|
|
||||||
if (qp->hdq_rdptr >= qp->hdq_top)
|
|
||||||
qp->hdq_rdptr = qp->hdq_buffer;
|
|
||||||
chSemSignalI(&qp->hdq_osem);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Writes a byte into the receive queue.
|
|
||||||
* @details If the queue is in transmission mode then the byte is lost.
|
|
||||||
*
|
|
||||||
* @param[in] qp pointer to a @p HalfDuplexQueue structure
|
|
||||||
* @param[in] b the byte value to be written
|
|
||||||
* @retval Q_OK if the operation is successful.
|
|
||||||
* @retval Q_FULL if the driver is in transmit mode or the receive queue is full.
|
|
||||||
* @note This function must be called with interrupts disabled or from an
|
|
||||||
* interrupt handler.
|
|
||||||
*/
|
|
||||||
msg_t chHDQPutReceiveI(HalfDuplexQueue *qp, uint8_t b) {
|
|
||||||
|
|
||||||
if (chHDQIsTransmitting(qp))
|
|
||||||
return Q_FULL;
|
|
||||||
|
|
||||||
if (chHDQIsFullReceive(qp))
|
|
||||||
return Q_FULL;
|
|
||||||
|
|
||||||
*qp->hdq_wrptr++ = b;
|
|
||||||
if (qp->hdq_wrptr >= qp->hdq_top)
|
|
||||||
qp->hdq_wrptr = qp->hdq_buffer;
|
|
||||||
chSemSignalI(&qp->hdq_isem);
|
|
||||||
return Q_OK;
|
|
||||||
}
|
|
||||||
#endif /* CH_USE_QUEUES_HALFDUPLEX */
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -123,96 +123,4 @@ dflags_t chFDDGetAndClearFlags(FullDuplexDriver *sd) {
|
||||||
}
|
}
|
||||||
#endif /* CH_USE_SERIAL_FULLDUPLEX */
|
#endif /* CH_USE_SERIAL_FULLDUPLEX */
|
||||||
|
|
||||||
#if CH_USE_SERIAL_HALFDUPLEX
|
|
||||||
/**
|
|
||||||
* @brief Initializes a generic half duplex driver.
|
|
||||||
* @details The HW dependent part of the initialization has to be performed
|
|
||||||
* outside, usually in the hardware initialization code.
|
|
||||||
*
|
|
||||||
* @param[out] sd pointer to a @p HalfDuplexDriver structure
|
|
||||||
* @param[in] b pointer to a memory area allocated for the queue buffer
|
|
||||||
* @param[in] size the buffer size
|
|
||||||
* @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] onotify pointer to a callback function that is invoked when
|
|
||||||
* some data is written in the queue. The value can be
|
|
||||||
* @p NULL.
|
|
||||||
*/
|
|
||||||
void chHDDInit(HalfDuplexDriver *sd, uint8_t *b, size_t size,
|
|
||||||
qnotify_t inotify, qnotify_t onotify) {
|
|
||||||
|
|
||||||
chDbgCheck((sd != NULL) && (b != NULL) && (size > 0), "chHDDInit");
|
|
||||||
|
|
||||||
chHDQInit(&sd->sd_queue, b, size, inotify, onotify);
|
|
||||||
chEvtInit(&sd->sd_ievent);
|
|
||||||
chEvtInit(&sd->sd_oevent);
|
|
||||||
chEvtInit(&sd->sd_sevent);
|
|
||||||
sd->sd_flags = SD_NO_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handles incoming data.
|
|
||||||
* @details This function must be called from the input interrupt service
|
|
||||||
* routine in order to enqueue incoming data and generate the
|
|
||||||
* related events.
|
|
||||||
* @param[in] sd pointer to a @p FullDuplexDriver structure
|
|
||||||
* @param[in] b the byte to be written in the driver's input queue
|
|
||||||
*/
|
|
||||||
void chHDDIncomingDataI(HalfDuplexDriver *sd, uint8_t b) {
|
|
||||||
|
|
||||||
if (chHDQPutReceiveI(&sd->sd_queue, b) < Q_OK)
|
|
||||||
chHDDAddFlagsI(sd, SD_OVERRUN_ERROR);
|
|
||||||
else
|
|
||||||
chEvtBroadcastI(&sd->sd_ievent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handles outgoing data.
|
|
||||||
* @details Must be called from the output interrupt service routine in order
|
|
||||||
* to get the next byte to be transmitted.
|
|
||||||
*
|
|
||||||
* @param[in] sd pointer to a @p HalfDuplexDriver structure
|
|
||||||
* @return The byte value read from the driver's output queue.
|
|
||||||
* @retval Q_EMPTY if the queue is empty (the lower driver usually disables
|
|
||||||
* the interrupt source when this happens).
|
|
||||||
*/
|
|
||||||
msg_t chHDDRequestDataI(HalfDuplexDriver *sd) {
|
|
||||||
|
|
||||||
msg_t b = chHDQGetTransmitI(&sd->sd_queue);
|
|
||||||
if (b < Q_OK)
|
|
||||||
chEvtBroadcastI(&sd->sd_oevent);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Handles communication events/errors.
|
|
||||||
* @details Must be called from the I/O interrupt service routine in order to
|
|
||||||
* notify I/O conditions as errors, signals change etc.
|
|
||||||
*
|
|
||||||
* @param[in] sd pointer to a @p HalfDuplexDriver structure
|
|
||||||
* @param[in] mask condition flags to be added to the mask
|
|
||||||
*/
|
|
||||||
void chHDDAddFlagsI(HalfDuplexDriver *sd, dflags_t mask) {
|
|
||||||
|
|
||||||
sd->sd_flags |= mask;
|
|
||||||
chEvtBroadcastI(&sd->sd_sevent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns and clears the errors mask associated to the driver.
|
|
||||||
*
|
|
||||||
* @param[in] sd pointer to a @p HalfDuplexDriver structure
|
|
||||||
* @return The condition flags modified since last time this function was
|
|
||||||
* invoked.
|
|
||||||
*/
|
|
||||||
dflags_t chHDDGetAndClearFlags(HalfDuplexDriver *sd) {
|
|
||||||
dflags_t mask;
|
|
||||||
|
|
||||||
mask = sd->sd_flags;
|
|
||||||
sd->sd_flags = SD_NO_ERROR;
|
|
||||||
return mask;
|
|
||||||
}
|
|
||||||
#endif /* CH_USE_SERIAL_HALFDUPLEX */
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -43,9 +43,13 @@ typedef void (*qnotify_t)(void);
|
||||||
|
|
||||||
#if CH_USE_QUEUES
|
#if CH_USE_QUEUES
|
||||||
/**
|
/**
|
||||||
* @brief I/O queue structure.
|
* @brief Generic I/O queue structure.
|
||||||
* @details This structure is used by both Input and Output Queues,
|
* @details This structure represents a generic Input or Output asymmetrical
|
||||||
* the difference is on how the semaphore is initialized.
|
* queue. The queue is asymmetrical because one end is meant to be
|
||||||
|
* accessed from a thread context, and thus can be blocking, the other
|
||||||
|
* end is accessible from interrupt handlers or from within a kernel
|
||||||
|
* lock zone (see <b>I-Locked</b> and <b>S-Locked</b> states in
|
||||||
|
* @ref system_states) and is non-blocking.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *q_buffer; /**< Pointer to the queue buffer.*/
|
uint8_t *q_buffer; /**< Pointer to the queue buffer.*/
|
||||||
|
@ -55,7 +59,7 @@ typedef struct {
|
||||||
uint8_t *q_rdptr; /**< Read pointer.*/
|
uint8_t *q_rdptr; /**< Read pointer.*/
|
||||||
Semaphore q_sem; /**< Counter @p Semaphore.*/
|
Semaphore q_sem; /**< Counter @p Semaphore.*/
|
||||||
qnotify_t q_notify; /**< Data notification callback.*/
|
qnotify_t q_notify; /**< Data notification callback.*/
|
||||||
} Queue;
|
} GenericQueue;
|
||||||
|
|
||||||
/** Returns the queue's buffer size. */
|
/** Returns the queue's buffer size. */
|
||||||
#define chQSize(q) ((q)->q_top - (q)->q_buffer)
|
#define chQSize(q) ((q)->q_top - (q)->q_buffer)
|
||||||
|
@ -68,110 +72,86 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
#define chQSpace(q) chSemGetCounterI(&(q)->q_sem)
|
#define chQSpace(q) chSemGetCounterI(&(q)->q_sem)
|
||||||
|
|
||||||
/** Evaluates to TRUE if the specified Input Queue is empty. */
|
/**
|
||||||
|
* @brief Input queue structure.
|
||||||
|
* @details This structure represents a generic asymmetrical input queue.
|
||||||
|
* Writing in the queue is non-blocking and can be performed from
|
||||||
|
* interrupt handlers or from within a kernel lock zone (see
|
||||||
|
* <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
|
||||||
|
* Reading the queue can be a blocking operation and is supposed to
|
||||||
|
* be performed by a system thread.
|
||||||
|
* @extends GenericQueue
|
||||||
|
*/
|
||||||
|
typedef GenericQueue InputQueue;
|
||||||
|
|
||||||
|
/** Evaluates to @p TRUE if the specified Input Queue is empty. */
|
||||||
#define chIQIsEmpty(q) (chQSpace(q) <= 0)
|
#define chIQIsEmpty(q) (chQSpace(q) <= 0)
|
||||||
|
|
||||||
/** Evaluates to TRUE if the specified Input Queue is full. */
|
/** Evaluates to @p TRUE if the specified Input Queue is full. */
|
||||||
#define chIQIsFull(q) (chQSpace(q) >= chQSize(q))
|
#define chIQIsFull(q) (chQSpace(q) >= chQSize(q))
|
||||||
|
|
||||||
/** Evaluates to TRUE if the specified Output Queue is empty. */
|
/**
|
||||||
|
* @brief Input queue read.
|
||||||
|
* @details This function reads a byte value from an input queue. If the queue
|
||||||
|
* is empty then the calling thread is suspended until a byte arrives
|
||||||
|
* in the queue.
|
||||||
|
*
|
||||||
|
* @param[in] iqp pointer to an @p InputQueue structure
|
||||||
|
* @return A byte value from the queue or:
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*/
|
||||||
|
#define chIQGet(iqp) chIQGetTimeout(iqp, TIME_INFINITE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue structure.
|
||||||
|
* @details This structure represents a generic asymmetrical output queue.
|
||||||
|
* Reading from the queue is non-blocking and can be performed from
|
||||||
|
* interrupt handlers or from within a kernel lock zone (see
|
||||||
|
* <b>I-Locked</b> and <b>S-Locked</b> states in @ref system_states).
|
||||||
|
* Writing the queue can be a blocking operation and is supposed to
|
||||||
|
* be performed by a system thread.
|
||||||
|
* @extends GenericQueue
|
||||||
|
*/
|
||||||
|
typedef GenericQueue OutputQueue;
|
||||||
|
|
||||||
|
/** Evaluates to @p TRUE if the specified Output Queue is empty. */
|
||||||
#define chOQIsEmpty(q) (chQSpace(q) >= chQSize(q))
|
#define chOQIsEmpty(q) (chQSpace(q) >= chQSize(q))
|
||||||
|
|
||||||
/** Evaluates to TRUE if the specified Output Queue is full. */
|
/** Evaluates to @p TRUE if the specified Output Queue is full. */
|
||||||
#define chOQIsFull(q) (chQSpace(q) <= 0)
|
#define chOQIsFull(q) (chQSpace(q) <= 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output queue write.
|
||||||
|
* @details This function writes a byte value to an output queue. If the queue
|
||||||
|
* is full then the calling thread is suspended until there is space
|
||||||
|
* in the queue.
|
||||||
|
*
|
||||||
|
* @param[in] oqp pointer to an @p OutputQueue structure
|
||||||
|
* @param[in] b the byte value to be written in the queue
|
||||||
|
* @return The operation status:
|
||||||
|
* @retval Q_OK if the operation succeeded.
|
||||||
|
* @retval Q_RESET if the queue was reset.
|
||||||
|
*/
|
||||||
|
#define chOQPut(oqp, b) chOQPutTimeout(oqp, b, TIME_INFINITE)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
/*
|
void chIQInit(InputQueue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
|
||||||
* Input Queues functions. An Input Queue is usually written into by an
|
void chIQResetI(InputQueue *qp);
|
||||||
* interrupt handler and read from a thread.
|
msg_t chIQPutI(InputQueue *qp, uint8_t b);
|
||||||
*/
|
msg_t chIQGetTimeout(InputQueue *qp, systime_t timeout);
|
||||||
void chIQInit(Queue *qp, uint8_t *buffer, size_t size, qnotify_t inotify);
|
size_t chIQRead(InputQueue *qp, uint8_t *buffer, size_t n);
|
||||||
void chIQReset(Queue *qp);
|
void chOQInit(OutputQueue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
|
||||||
msg_t chIQPutI(Queue *qp, uint8_t b);
|
void chOQResetI(OutputQueue *queue);
|
||||||
msg_t chIQGet(Queue *qp);
|
msg_t chOQPutTimeout(OutputQueue *queue, uint8_t b, systime_t timeout);
|
||||||
size_t chIQRead(Queue *qp, uint8_t *buffer, size_t n);
|
msg_t chOQGetI(OutputQueue *queue);
|
||||||
#if CH_USE_QUEUES_TIMEOUT
|
size_t chOQWrite(OutputQueue *queue, uint8_t *buffer, size_t n);
|
||||||
msg_t chIQGetTimeout(Queue *qp, systime_t time);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Output Queues functions. An Output Queue is usually written into by a
|
|
||||||
* thread and read from an interrupt handler.
|
|
||||||
*/
|
|
||||||
void chOQInit(Queue *queue, uint8_t *buffer, size_t size, qnotify_t onotify);
|
|
||||||
void chOQReset(Queue *queue);
|
|
||||||
void chOQPut(Queue *queue, uint8_t b);
|
|
||||||
msg_t chOQGetI(Queue *queue);
|
|
||||||
size_t chOQWrite(Queue *queue, uint8_t *buffer, size_t n);
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif /* CH_USE_QUEUES */
|
#endif /* CH_USE_QUEUES */
|
||||||
|
|
||||||
#if CH_USE_QUEUES_HALFDUPLEX
|
|
||||||
/**
|
|
||||||
* @brief Half duplex queue structure.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
uint8_t *hdq_buffer; /**< Pointer to the queue buffer.*/
|
|
||||||
uint8_t *hdq_top; /**< Pointer to the first location
|
|
||||||
after the buffer. */
|
|
||||||
uint8_t *hdq_wrptr; /**< Write pointer.*/
|
|
||||||
uint8_t *hdq_rdptr; /**< Read pointer.*/
|
|
||||||
Semaphore hdq_isem; /**< Input counter @p Semaphore.*/
|
|
||||||
Semaphore hdq_osem; /**< Output counter @p Semaphore.*/
|
|
||||||
qnotify_t hdq_inotify; /**< Input data notification
|
|
||||||
callback.*/
|
|
||||||
qnotify_t hdq_onotify; /**< Output data notification
|
|
||||||
callback.*/
|
|
||||||
} HalfDuplexQueue;
|
|
||||||
|
|
||||||
/** Returns the queue's buffer size. */
|
|
||||||
#define chHDQSize(q) ((q)->hdq_top - (q)->hdq_buffer)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the queue space when in transmission mode.
|
|
||||||
* @note The returned value can be less than zero when there are waiting
|
|
||||||
* threads on the internal semaphore.
|
|
||||||
*/
|
|
||||||
#define chHDQEmptySpace(q) chSemGetCounterI(&(q)->hdq_osem)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of the bytes in the queue when in receive mode.
|
|
||||||
* @note The returned value can be less than zero when there are waiting
|
|
||||||
* threads on the internal semaphore.
|
|
||||||
*/
|
|
||||||
#define chHDQFilledSpace(q) chSemGetCounterI(&(q)->hdq_isem)
|
|
||||||
|
|
||||||
/** Evaluates to TRUE if the queue is in transmit mode. */
|
|
||||||
#define chHDQIsTransmitting(q) (chHDQEmptySpace(q) < chHDQSize(q))
|
|
||||||
|
|
||||||
/** Evaluates to TRUE if the queue is in receive mode. */
|
|
||||||
#define chHDQIsReceiving(q) (chHDQEmptySpaceQ(q) >= chHDQSize(q))
|
|
||||||
|
|
||||||
/** Evaluates to TRUE if the receive queue is full. */
|
|
||||||
#define chHDQIsFullReceive(q) (chHDQFilledSpace(q) >= chHDQSize(q))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void chHDQInit(HalfDuplexQueue *qp, uint8_t *buffer, size_t size,
|
|
||||||
qnotify_t inotify, qnotify_t onotify);
|
|
||||||
msg_t chHDQGetReceive(HalfDuplexQueue *qp);
|
|
||||||
void chHDQPutTransmit(HalfDuplexQueue *qp, uint8_t b);
|
|
||||||
msg_t chHDQGetTransmitI(HalfDuplexQueue *qp);
|
|
||||||
msg_t chHDQPutReceiveI(HalfDuplexQueue *qp, uint8_t b);
|
|
||||||
#if CH_USE_QUEUES_TIMEOUT
|
|
||||||
msg_t chHDQGetReceiveTimeout(HalfDuplexQueue *qp, systime_t time);
|
|
||||||
#endif
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* CH_USE_QUEUES_HALFDUPLEX */
|
|
||||||
|
|
||||||
#endif /* _QUEUES_H_ */
|
#endif /* _QUEUES_H_ */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -54,14 +54,14 @@ typedef struct {
|
||||||
|
|
||||||
/** Input queue. Incoming data can be read from this queue by using the
|
/** Input queue. Incoming data can be read from this queue by using the
|
||||||
* queues APIs.*/
|
* queues APIs.*/
|
||||||
Queue sd_iqueue;
|
InputQueue sd_iqueue;
|
||||||
/** Data Available @p EventSource. This event is generated when some incoming
|
/** Data Available @p EventSource. This event is generated when some incoming
|
||||||
* data is inserted in the Input @p Queue.*/
|
* data is inserted in the Input @p Queue.*/
|
||||||
EventSource sd_ievent;
|
EventSource sd_ievent;
|
||||||
|
|
||||||
/** Output queue. Outgoing data can be written to this Output @p Queue by
|
/** Output queue. Outgoing data can be written to this Output @p Queue by
|
||||||
* using the queues APIs.*/
|
* using the queues APIs.*/
|
||||||
Queue sd_oqueue;
|
OutputQueue sd_oqueue;
|
||||||
/** Data Transmitted @p EventSource. This event is generated when the
|
/** Data Transmitted @p EventSource. This event is generated when the
|
||||||
* Output @p Queue is empty.*/
|
* Output @p Queue is empty.*/
|
||||||
EventSource sd_oevent;
|
EventSource sd_oevent;
|
||||||
|
@ -110,58 +110,6 @@ extern "C" {
|
||||||
|
|
||||||
#endif /* CH_USE_SERIAL_FULLDUPLEX */
|
#endif /* CH_USE_SERIAL_FULLDUPLEX */
|
||||||
|
|
||||||
#if CH_USE_SERIAL_HALFDUPLEX
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Full Duplex Serial Driver main structure.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
/** Data queue. Transmit/receive @p HalfDuplexQueue.*/
|
|
||||||
HalfDuplexQueue sd_queue;
|
|
||||||
/** Data Available @p EventSource. This event is generated when some
|
|
||||||
* incoming data is inserted in the receive queue.*/
|
|
||||||
EventSource sd_ievent;
|
|
||||||
/** Data Transmitted @p EventSource. This event is generated when the
|
|
||||||
* transmission queue is empty and the driver can either transmit more
|
|
||||||
* data or enter receive mode.*/
|
|
||||||
EventSource sd_oevent;
|
|
||||||
/** I/O driver status flags. This field should not be read directly but
|
|
||||||
* the @p chHDDGetAndClearFlags() funtion should be used
|
|
||||||
* instead.*/
|
|
||||||
dflags_t sd_flags;
|
|
||||||
/** Status Change Event Source. This event is generated when a condition
|
|
||||||
* flag was changed.*/
|
|
||||||
EventSource sd_sevent;
|
|
||||||
} HalfDuplexDriver;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void chHDDInit(HalfDuplexDriver *sd, uint8_t *b, size_t size,
|
|
||||||
qnotify_t inotify, qnotify_t onotify);
|
|
||||||
void chHDDIncomingDataI(HalfDuplexDriver *sd, uint8_t b);
|
|
||||||
msg_t chHDDRequestDataI(HalfDuplexDriver *sd);
|
|
||||||
void chHDDAddFlagsI(HalfDuplexDriver *sd, dflags_t mask);
|
|
||||||
dflags_t chHDDGetAndClearFlags(HalfDuplexDriver *sd);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @see chHDQGetReceive()*/
|
|
||||||
#define chHDDGetReceive(sd) \
|
|
||||||
chHDQGetReceive(&(sd)->sd_queue)
|
|
||||||
|
|
||||||
/** @see chHDQGetReceiveTimeout()*/
|
|
||||||
#define chHDDGetReceiveTimeout(sd, t) \
|
|
||||||
chHDQGetReceiveTimeout(&(sd)->sd_queue, t)
|
|
||||||
|
|
||||||
/** @see chHDQPutTransmit()*/
|
|
||||||
#define chHDDPutTransmit(sd, b) \
|
|
||||||
chHDQPutTransmit(&(sd)->sd_queue, b)
|
|
||||||
|
|
||||||
#endif /* CH_USE_SERIAL_HALFDUPLEX */
|
|
||||||
|
|
||||||
#endif /* _SERIAL_H_ */
|
#endif /* _SERIAL_H_ */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -318,7 +318,7 @@ static char *bmk8_gettest(void) {
|
||||||
|
|
||||||
static void bmk8_execute(void) {
|
static void bmk8_execute(void) {
|
||||||
static uint8_t ib[16];
|
static uint8_t ib[16];
|
||||||
static Queue iq;
|
static InputQueue iq;
|
||||||
|
|
||||||
chIQInit(&iq, ib, sizeof(ib), NULL);
|
chIQInit(&iq, ib, sizeof(ib), NULL);
|
||||||
uint32_t n = 0;
|
uint32_t n = 0;
|
||||||
|
|
Loading…
Reference in New Issue