static void queues1_execute(void) { unsigned i; size_t n; /* Initial empty state */ test_assert(1, chIQIsEmptyI(&iq), "not empty"); /* Queue filling */ for (i = 0; i < TEST_QUEUES_SIZE; i++) chIQPutI(&iq, 'A' + i); test_assert(2, chIQIsFullI(&iq), "still has space"); test_assert(3, chIQPutI(&iq, 0) == Q_FULL, "failed to report Q_FULL"); /* Queue emptying */ for (i = 0; i < TEST_QUEUES_SIZE; i++) test_emit_token(chIQGet(&iq)); test_assert(4, chIQIsEmptyI(&iq), "still full"); test_assert_sequence(5, "ABCD"); /* Queue filling again */ for (i = 0; i < TEST_QUEUES_SIZE; i++) chIQPutI(&iq, 'A' + i); /* Reading the whole thing */ n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE * 2, TIME_IMMEDIATE); test_assert(6, n == TEST_QUEUES_SIZE, "wrong returned size"); test_assert(7, chIQIsEmptyI(&iq), "still full"); /* Queue filling again */ for (i = 0; i < TEST_QUEUES_SIZE; i++) chIQPutI(&iq, 'A' + i); /* Partial reads */ n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE); test_assert(8, n == TEST_QUEUES_SIZE / 2, "wrong returned size"); n = chIQReadTimeout(&iq, wa[1], TEST_QUEUES_SIZE / 2, TIME_IMMEDIATE); test_assert(9, n == TEST_QUEUES_SIZE / 2, "wrong returned size"); test_assert(10, chIQIsEmptyI(&iq), "still full"); /* Testing reset */ chIQPutI(&iq, 0); chIQResetI(&iq); test_assert(11, chIQGetFullI(&iq) == 0, "still full"); threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread1, NULL); test_assert(12, chIQGetFullI(&iq) == 0, "not empty"); test_wait_threads(); /* Timeout */ test_assert(13, chIQGetTimeout(&iq, 10) == Q_TIMEOUT, "wrong timeout return"); }
/** * @brief Input queue read with timeout. * @details The function reads data from an input queue into a buffer. The * 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 callback is invoked before reading each character from the * buffer or before entering the state @p CH_STATE_WTQUEUE. * * @param[in] iqp pointer to an @p input_queue_t structure * @param[out] bp pointer to the data buffer * @param[in] n the maximum amount of data to be transferred, the * value 0 is reserved * @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. * * @api */ size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp, size_t n, systime_t time) { qnotify_t nfy = iqp->q_notify; size_t r = 0; chDbgCheck(n > 0); chSysLock(); while (true) { if (nfy) nfy(iqp); while (chIQIsEmptyI(iqp)) { if (chThdEnqueueTimeoutS(&iqp->q_waiting, time) != Q_OK) { chSysUnlock(); return r; } } iqp->q_counter--; *bp++ = *iqp->q_rdptr++; if (iqp->q_rdptr >= iqp->q_top) iqp->q_rdptr = iqp->q_buffer; chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ r++; if (--n == 0) return r; chSysLock(); } }
/** * @brief Input queue read with timeout. * @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 or a timeout occurs. * @note The callback is invoked before reading the character from the * buffer or before entering the state @p CH_STATE_WTQUEUE. * * @param[in] iqp pointer to an @p input_queue_t 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 A byte value from the queue. * @retval Q_TIMEOUT if the specified time expired. * @retval Q_RESET if the queue has been reset. * * @api */ msg_t chIQGetTimeout(input_queue_t *iqp, systime_t timeout) { uint8_t b; chSysLock(); if (iqp->notify != NULL) { iqp->notify(iqp); } while (chIQIsEmptyI(iqp)) { msg_t msg = chThdEnqueueTimeoutS(&iqp->waiting, timeout); if (msg < Q_OK) { chSysUnlock(); return msg; } } iqp->counter--; b = *iqp->rdptr++; if (iqp->rdptr >= iqp->top) { iqp->rdptr = iqp->buffer; } chSysUnlock(); return (msg_t)b; }
/** * @brief Input queue read with timeout. * @details The function reads data from an input queue into a buffer. The * 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 callback is invoked before reading each character from the * buffer or before entering the state @p THD_STATE_WTQUEUE. * * @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, the * value 0 is reserved * @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. * * @api */ size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp, size_t n, systime_t time) { qnotify_t nfy = iqp->q_notify; size_t r = 0; chDbgCheck(n > 0, "chIQReadTimeout"); chSysLock(); while (TRUE) { if (nfy) nfy(iqp); while (chIQIsEmptyI(iqp)) { if (qwait((GenericQueue *)iqp, time) != Q_OK) { chSysUnlock(); return r; } } iqp->q_counter--; *bp++ = *iqp->q_rdptr++; if (iqp->q_rdptr >= iqp->q_top) iqp->q_rdptr = iqp->q_buffer; chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ r++; if (--n == 0) return r; chSysLock(); } }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serve_interrupt(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; uint8_t s1 = u->S1; if (s1 & UARTx_S1_RDRF) { osalSysLockFromISR(); if (chIQIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); if (chIQPutI(&sdp->iqueue, u->D) < Q_OK) chnAddFlagsI(sdp, SD_OVERRUN_ERROR); osalSysUnlockFromISR(); } if (s1 & UARTx_S1_TDRE) { msg_t b; osalSysLockFromISR(); b = chOQGetI(&sdp->oqueue); osalSysUnlockFromISR(); if (b < Q_OK) { osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); osalSysUnlockFromISR(); u->C2 &= ~UARTx_C2_TIE; } else { u->D = b; } } }
/** * @brief Input queue read with timeout. * @details The function reads data from an input queue into a buffer. The * 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 before entering a sleep state and at * the end of the transfer. * * @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, the * value 0 is reserved * @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. * * @api */ size_t chIQReadTimeout(InputQueue *iqp, uint8_t *bp, size_t n, systime_t time) { qnotify_t nfy = iqp->q_notify; size_t r = 0; chDbgCheck(n > 0, "chIQReadTimeout"); chSysLock(); while (TRUE) { if (chIQIsEmptyI(iqp)) { if (nfy) nfy(iqp); if ((chSemWaitTimeoutS(&iqp->q_sem, time) != RDY_OK)) { chSysUnlock(); return r; } } else chSemFastWaitI(&iqp->q_sem); *bp++ = *iqp->q_rdptr++; if (iqp->q_rdptr >= iqp->q_top) iqp->q_rdptr = iqp->q_buffer; chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ r++; if (--n == 0) { chSysLock(); if (nfy) nfy(iqp); chSysUnlock(); return r; } chSysLock(); } }
/** * @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. * @note The incoming data event is only generated when the input queue * becomes non-empty. * @note In order to gain some performance it is suggested to not use * this function directly but copy this code directly into the * interrupt service routine. * * @param[in] sdp pointer to a @p SerialDriver structure * @param[in] b the byte to be written in the driver's Input Queue * * @iclass */ void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { chDbgCheckClassI(); chDbgCheck(sdp != NULL, "sdIncomingDataI"); if (chIQIsEmptyI(&sdp->iqueue)) chIOAddFlagsI(sdp, IO_INPUT_AVAILABLE); if (chIQPutI(&sdp->iqueue, b) < Q_OK) chIOAddFlagsI(sdp, SD_OVERRUN_ERROR); }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we dont want * to go through the whole ISR and have another interrupt soon after. * * @param[in] sdp communication channel associated to the UART */ static void serve_interrupt(SerialDriver *sdp) { UART *u = sdp->uart; while (TRUE) { switch (u->UART_IIR & IIR_SRC_MASK) { case IIR_SRC_NONE: return; case IIR_SRC_ERROR: set_error(sdp, u->UART_LSR); break; case IIR_SRC_TIMEOUT: case IIR_SRC_RX: chSysLockFromIsr(); if (chIQIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); chSysUnlockFromIsr(); while (u->UART_LSR & LSR_RBR_FULL) { chSysLockFromIsr(); if (chIQPutI(&sdp->iqueue, u->UART_RBR) < Q_OK) chnAddFlagsI(sdp, SD_OVERRUN_ERROR); chSysUnlockFromIsr(); } break; case IIR_SRC_TX: { int i = LPC214x_UART_FIFO_PRELOAD; do { msg_t b; chSysLockFromIsr(); b = chOQGetI(&sdp->oqueue); chSysUnlockFromIsr(); if (b < Q_OK) { u->UART_IER &= ~IER_THRE; chSysLockFromIsr(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); chSysUnlockFromIsr(); break; } u->UART_THR = b; } while (--i); } break; default: (void) u->UART_THR; (void) u->UART_RBR; } } }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serve_interrupt(SerialDriver *sdp) { LPC_USART_TypeDef *u = sdp->uart; while (u->INTSTAT) { if (u->INTSTAT & STAT_RXRDY) { chSysLockFromIsr(); if (chIQIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); if (chIQPutI(&sdp->iqueue, u->RXDATA) < Q_OK) chnAddFlagsI(sdp, SD_OVERRUN_ERROR); chSysUnlockFromIsr(); } if (u->INTSTAT & STAT_TXRDY) { msg_t b; chSysLockFromIsr(); b = chOQGetI(&sdp->oqueue); chSysUnlockFromIsr(); if (b < Q_OK) { u->INTENCLR = STAT_TXRDY; chSysLockFromIsr(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); chSysUnlockFromIsr(); break; } else { u->TXDATA = b; } } if (u->INTSTAT & (STAT_OVERRUN | STAT_DELTARXBRK | STAT_FRAMERR | STAT_PARITYERR) ) { IOREG32 stat = u->STAT; set_error(sdp, stat); u->STAT = stat; } } }
/** * @brief Input queue read with timeout. * @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 or a timeout occurs. * @note The callback is invoked before reading the character from the * buffer or before entering the state @p CH_STATE_WTQUEUE. * * @param[in] iqp pointer to an @p input_queue_t structure * @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 A byte value from the queue. * @retval Q_TIMEOUT if the specified time expired. * @retval Q_RESET if the queue has been reset. * * @api */ msg_t chIQGetTimeout(input_queue_t *iqp, systime_t time) { uint8_t b; chSysLock(); if (iqp->q_notify) iqp->q_notify(iqp); while (chIQIsEmptyI(iqp)) { msg_t msg; if ((msg = chThdEnqueueTimeoutS(&iqp->q_waiting, time)) < Q_OK) { chSysUnlock(); return msg; } } iqp->q_counter--; b = *iqp->q_rdptr++; if (iqp->q_rdptr >= iqp->q_top) iqp->q_rdptr = iqp->q_buffer; chSysUnlock(); return b; }
/** * @brief Input queue read with timeout. * @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 or a timeout occurs. * @note The callback is invoked before reading the character from the * buffer or before entering the state @p THD_STATE_WTQUEUE. * * @param[in] iqp pointer to an @p InputQueue structure * @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 A byte value from the queue. * @retval Q_TIMEOUT if the specified time expired. * @retval Q_RESET if the queue has been reset. * * @api */ msg_t chIQGetTimeout(InputQueue *iqp, systime_t time) { uint8_t b; chSysLock(); if (iqp->q_notify) iqp->q_notify(iqp); while (chIQIsEmptyI(iqp)) { msg_t msg; if ((msg = qwait((GenericQueue *)iqp, time)) < Q_OK) { chSysUnlock(); return msg; } } iqp->q_counter--; b = *iqp->q_rdptr++; if (iqp->q_rdptr >= iqp->q_top) iqp->q_rdptr = iqp->q_buffer; chSysUnlock(); return b; }
bool InQueue::isEmptyI(void) { return (bool)chIQIsEmptyI(&iq); }
static bool_t getwouldblock(void *ip) { return chIQIsEmptyI(&((SerialDriver *)ip)->iqueue); }