/***************************************************************************//** * @brief * Reset stall state on a stalled (halted) endpoint. * * @param[in] epAddr * The address of the endpoint to un-stall. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int USBD_UnStallEp( int epAddr ) { USB_Status_TypeDef retVal; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal request" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ep->num == 0 ) { DEBUG_USB_API_PUTS( "\nUSBD_UnStallEp(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } INT_Disable(); retVal = USBDHAL_UnStallEp( ep ); INT_Enable(); if ( retVal != USB_STATUS_OK ) { retVal = USB_STATUS_ILLEGAL; } return retVal; }
//-------------------------------------------------------------------------------- int main(void) { /* Init System Timer to fire interrupts at 1ms - timer tick */ OCR0 = 125; // set output compare match register, timer tick 1ms TCCR0 = (1 << WGM01) + (1 << CS02) + (1 << CS00); //clear on compare match mode, Fclk/128 TIMSK |= (1 << OCIE0); // enable output compare 2 interrupt TCNT0 = 0x00; // clear timer2 register uSMARTX_Init(uSmartXTaskTable); /* Append timeout trigger function. The trigger function will be executed after * there is no write/read access if the buffer contains some unread data. */ BUF_AppendToutFxn(&BUF, 10 /*10 ms*/, &TimeoutFxn); /* Append level trigger function. The trigger function will be executed after * the buffer fills to a level of 4. The function will be re-triggered after the * buffer is completely emptied out. */ BUF_AppendTrgFxn(&BUF, 4, &TriggerFxn); /* Enable interrupts. */ INT_Enable(); while(1) { if(uSMARTX_Scheduler() == SYS_ERROR) break; } /* Handle error here. */ return 0; }
void service_net () { while (interrupts > 0) { NRF_CE_lo; uint8_t status = NRF_ReadRegister(NRF_STATUS); RXEN_lo; // received a packet if (status & 0x40) { printf("Radio received a packet\n"); readPacket(); } else if (status & 0x20) { // packet was sent printf("Radio successfully sent the packet\n"); NRF_WriteRegister(NRF_STATUS, 0x10); } else if (status & 0x10) { // packet failed to send printf("Radio failed to send the packet\n"); NRF_WriteRegister(NRF_STATUS, 0x20); } RXEN_hi; NRF_CE_hi; INT_Disable(); interrupts--; INT_Enable(); } }
/**************************************************************************//** * @brief Sleep in EM1 until DMA transfer is done *****************************************************************************/ void sleepUntilDmaDone(void) { /* Enter EM1 while DMA transfer is active to save power. Note that * interrupts are disabled to prevent the ISR from being triggered * after checking the transferActive flag, but before entering * sleep. If this were to happen, there would be no interrupt to wake * the core again and the MCU would be stuck in EM1. While the * core is in sleep, pending interrupts will still wake up the * core and the ISR will be triggered after interrupts are enabled * again. */ bool isActive = false; while(1) { INT_Disable(); isActive = spiDmaIsActive(); if ( isActive ) { EMU_EnterEM1(); } INT_Enable(); // Exit the loop if transfer has completed if ( !isActive ) { DPRINT("SPI DONE"); break; } } }
/***************************************************************************//** * @brief * Get time left before a given timer expires. * * @param[in] id The id of the timer to query. * * @param[out] timeRemaining Time left expressed in milliseconds. * Only valid if return status is ECODE_EMDRV_RTCDRV_OK. * @return * @ref ECODE_EMDRV_RTCDRV_OK on success.@n * @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value. @n * @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED if the timer is not reserved.@n * @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING if the timer is not running.@n * @ref ECODE_EMDRV_RTCDRV_PARAM_ERROR if an invalid timeRemaining pointer * was supplied. ******************************************************************************/ Ecode_t RTCDRV_TimeRemaining( RTCDRV_TimerID_t id, uint32_t *timeRemaining ) { uint64_t tmp; uint32_t timeLeft, currentCnt, lastRtcStart; // Check if valid timer ID. if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) { return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID; } // Check pointer validity. if ( timeRemaining == NULL ) { return ECODE_EMDRV_RTCDRV_PARAM_ERROR; } INT_Disable(); // Check if timer is reserved. if ( ! timer[ id ].allocated ) { INT_Enable(); return ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED; } // Check if timer is running. if ( ! timer[ id ].running ) { INT_Enable(); return ECODE_EMDRV_RTCDRV_TIMER_NOT_RUNNING; } timeLeft = timer[ id ].remaining; currentCnt = RTC_COUNTERGET(); lastRtcStart = lastStart; INT_Enable(); // Get number of RTC clock ticks elapsed since last RTC reschedule. currentCnt = TIMEDIFF( currentCnt, lastRtcStart ); if ( currentCnt > timeLeft ) { timeLeft = 0; } else { timeLeft -= currentCnt; } tmp = TICKS_TO_MSEC( timeLeft ); *timeRemaining = tmp; return ECODE_EMDRV_RTCDRV_OK; }
/***************************************************************************//** * @brief * Abort a pending transfer on a specific endpoint. * * @param[in] epAddr * The address of the endpoint to abort. ******************************************************************************/ int USBD_AbortTransfer( int epAddr ) { USB_XferCompleteCb_TypeDef callback; USBD_Ep_TypeDef *ep = USBD_GetEpFromAddr( epAddr ); if ( ep == NULL ) { DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } if ( ep->num == 0 ) { DEBUG_USB_API_PUTS( "\nUSBD_AbortTransfer(), Illegal endpoint" ); EFM_ASSERT( false ); return USB_STATUS_ILLEGAL; } INT_Disable(); if ( ep->state == D_EP_IDLE ) { INT_Enable(); return USB_STATUS_OK; } USBD_AbortEp( ep ); ep->state = D_EP_IDLE; if ( ep->xferCompleteCb ) { callback = ep->xferCompleteCb; ep->xferCompleteCb = NULL; if ( ( dev->lastState == USBD_STATE_CONFIGURED ) && ( dev->state == USBD_STATE_ADDRESSED ) ) { USBDHAL_DeactivateEp( ep ); } DEBUG_TRACE_ABORT( USB_STATUS_EP_ABORTED ); callback( USB_STATUS_EP_ABORTED, ep->xferred, ep->remaining ); } INT_Enable(); return USB_STATUS_OK; }
/** Unblock the microcontroller from sleeping below a certain mode * * This will unblock sleep() from entering an energy mode below the one given. * -- To be called by peripheral HAL's -- * * This should be called after all transactions on a peripheral are done. */ void unblockSleepMode(sleepstate_enum minimumMode) { INT_Disable(); if(sleep_block_counter[minimumMode] > 0) { sleep_block_counter[minimumMode]--; } INT_Enable(); }
/***************************************************************************//** * @brief * Set wallclock time. * * @param[in] secs Value to set (seconds). * * @return * @ref ECODE_EMDRV_RTCDRV_OK ******************************************************************************/ Ecode_t RTCDRV_SetWallClock( uint32_t secs ) { INT_Disable(); wallClockTime = secs; wallClockInitTime = RTC_COUNTERGET(); INT_Enable(); return ECODE_EMDRV_RTCDRV_OK; }
void memoryTakeReference(void *handle) { INT_Disable(); if(memoryPtrFromHandle(handle) != NULL) { memoryObjs[(uint32_t)handle].refCount++; } INT_Enable(); }
void memoryFree(void *handle) { INT_Disable(); if(memoryPtrFromHandle(handle) != NULL) { memoryObjs[(uint32_t)handle].refCount--; } INT_Enable(); }
/***************************************************************************//** * @brief * Registers user callback for given pin number. * * @details * Use this function to register a callback which shall be called upon * interrupt generated from given pin number (port is irrelevant). Interrupt * itself must be configured externally. Function overwrites previously * registered callback. * * @param[in] pin * Pin number for the callback. * @param[in] callbackPtr * A pointer to callback function. ******************************************************************************/ void GPIOINT_CallbackRegister(uint8_t pin, GPIOINT_IrqCallbackPtr_t callbackPtr) { INT_Disable(); /* Dispatcher is used */ gpioCallbacks[pin] = callbackPtr; INT_Enable(); }
/***************************************************************************//** * @brief * Stop a given timer. * * @param[in] id The id of the timer to stop. * * @return * @ref ECODE_EMDRV_RTCDRV_OK on success.@n * @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value. @n * @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED if the timer is not reserved. ******************************************************************************/ Ecode_t RTCDRV_StopTimer( RTCDRV_TimerID_t id ) { // Check if valid timer ID. if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) { return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID; } INT_Disable(); if ( ! timer[ id ].allocated ) { INT_Enable(); return ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED; } timer[ id ].running = false; INT_Enable(); return ECODE_EMDRV_RTCDRV_OK; }
/***************************************************************************//** * @brief * Initialize DMADRV. * * @details * The DMA hw is initialized. * * @return * @ref ECODE_EMDRV_DMADRV_OK on success. On failure an appropriate * DMADRV @ref Ecode_t is returned. ******************************************************************************/ Ecode_t DMADRV_Init( void ) { int i; #if defined( EMDRV_DMADRV_UDMA ) DMA_Init_TypeDef dmaInit; #elif defined( EMDRV_DMADRV_LDMA ) LDMA_Init_t dmaInit = LDMA_INIT_DEFAULT; dmaInit.ldmaInitCtrlNumFixed = EMDRV_DMADRV_DMA_CH_PRIORITY; #endif INT_Disable(); if ( initialized ) { INT_Enable(); return ECODE_EMDRV_DMADRV_ALREADY_INITIALIZED; } initialized = true; INT_Enable(); if ( EMDRV_DMADRV_DMA_IRQ_PRIORITY > 7 ) { return ECODE_EMDRV_DMADRV_PARAM_ERROR; } for ( i=0; i < EMDRV_DMADRV_DMA_CH_COUNT; i++ ) { chTable[ i ].allocated = false; } #if defined( EMDRV_DMADRV_UDMA ) NVIC_SetPriority( DMA_IRQn, EMDRV_DMADRV_DMA_IRQ_PRIORITY ); dmaInit.hprot = 0; dmaInit.controlBlock = dmaControlBlock; DMA_Init( &dmaInit ); #elif defined( EMDRV_DMADRV_LDMA ) dmaInit.ldmaInitIrqPriority = EMDRV_DMADRV_DMA_IRQ_PRIORITY; LDMA_Init( &dmaInit ); #endif return ECODE_EMDRV_DMADRV_OK; }
Ecode_t COM_WriteString(COM_Port_t port, PGM_P string) { if (checkValidPort(port)==false) { return EMBER_ERR_FATAL; } uint8_t *fifohead= &comhandle[port]->txQueue->fifo[comhandle[port]->txQueue->head]; uint8_t length = 0; uint8_t wraplength = 0; while(*string != '\0') { while (! getOutputFifoSpace(port, 0)) {}; INT_Disable(); FIFO_ENQUEUE(comhandle[port]->txQueue,*string,comhandle[port]->txsize); INT_Enable(); string++; length++; // queue just wrapped if (comhandle[port]->txQueue->head == 0) { // store first transmit length wraplength = length; // transmit chunk if ( (port == COM_USART0) || (port == COM_USART1) || (port == COM_USART2) ) { while(UARTDRV_Transmit(comhandle[port]->uarthandle, fifohead, wraplength, unloadTxBuffer) != EMBER_SUCCESS); } #ifdef COM_VCP_ENABLE if (port == COM_VCP) { emDebugSendVuartMessage(comhandle[port]->txQueue->fifo, comhandle[port]->txsize); dequeueFifoBuffer(port, comhandle[port]->txsize); } #endif //COM_VCP_ENABLE // move fifohead back to start fifohead = comhandle[port]->txQueue->fifo; } } if ( length > wraplength) { if ( (port == COM_USART0) || (port == COM_USART1) || (port == COM_USART2) ) { while(UARTDRV_Transmit(comhandle[port]->uarthandle, fifohead, length - wraplength, unloadTxBuffer) != EMBER_SUCCESS); } #ifdef COM_VCP_ENABLE if (port == COM_VCP) { emDebugSendVuartMessage(comhandle[port]->txQueue->fifo, comhandle[port]->txsize); dequeueFifoBuffer(port, comhandle[port]->txsize); } #endif //COM_VCP_ENABLE } return EMBER_SUCCESS; }
/***************************************************************************//** * @brief * Perform a remote wakeup signalling sequence. * * @note * It is the responsibility of the application to ensure that remote wakeup * is not attempted before the device has been suspended for at least 5 * miliseconds. This function should not be called from within an interrupt * handler. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int USBD_RemoteWakeup( void ) { INT_Disable(); if ( ( dev->state != USBD_STATE_SUSPENDED ) || ( dev->remoteWakeupEnabled == false ) ) { INT_Enable(); DEBUG_USB_API_PUTS( "\nUSBD_RemoteWakeup(), Illegal remote wakeup" ); return USB_STATUS_ILLEGAL; } USBDHAL_SetRemoteWakeup(); INT_Enable(); USBTIMER_DelayMs( 10 ); INT_Disable(); USBDHAL_ClearRemoteWakeup(); INT_Enable(); return USB_STATUS_OK; }
/** * \brief Timer1 interrupt handler. */ void TIMER1_IRQHandler() { uint32_t flags; INT_Disable(); flags = TIMER_IntGet( TIMER1 ); _hal_tcCb(); TIMER_IntClear( TIMER1, flags ); INT_Enable(); }
bool buf_read_byte(buf_t *buf, uint8_t *data) { if (buf->count == 0) return false; // no data *data = buf->data[buf->read_idx++]; if (buf->read_idx >= buf->size) buf->read_idx = 0; INT_Disable(); buf->count--; INT_Enable(); return true; }
bool buf_write_byte(buf_t *buf, const uint8_t data) { if (buf->count >= buf->size) return false; // no room buf->data[buf->write_idx++] = data; if (buf->write_idx >= buf->size) buf->write_idx = 0; INT_Disable(); buf->count++; INT_Enable(); return true; }
/* reload buffer callbacks */ void updateBuffer(COM_FifoQueue_t *q, uint16_t xferred, uint16_t size) { // Update tail with additional xferred. Data should already be there INT_Disable(); if (xferred > q->pumped) { q->head = ((q->head - q->pumped + xferred) % size); q->used += xferred - q->pumped; q->pumped = xferred; } INT_Enable(); }
/***************************************************************************//** * @brief * Start a timer. * * @details * If the timer is already running, it will be restarted with new timeout. * * @param[in] id * Timer id (0..). * * @param[in] timeout * Number of milliseconds before timer will elapse. * * @param[in] callback * Function to be called on timer elapse, ref. @ref USBTIMER_Callback_TypeDef. ******************************************************************************/ void USBTIMER_Start( uint32_t id, uint32_t timeout, USBTIMER_Callback_TypeDef callback ) { uint32_t accumulated; USBTIMER_Timer_TypeDef *this, **last; INT_Disable(); if ( timers[ id ].running ) { USBTIMER_Stop( id ); } timers[ id ].running = true; timers[ id ].callback = callback; timers[ id ].next = NULL; if ( !head ) /* Queue empty ? */ { timers[ id ].timeout = timeout; head = &timers[ id ]; } else { this = head; last = &head; accumulated = 0; /* Do a sorted insert */ while ( this ) { if ( timeout < accumulated + this->timeout ) /* Insert before "this" ? */ { timers[ id ].timeout = timeout - accumulated; timers[ id ].next = this; *last = &timers[ id ]; this->timeout -= timers[ id ].timeout; /* Adjust timeout */ break; } else if ( this->next == NULL ) /* At end of queue ? */ { timers[ id ].timeout = timeout - accumulated - this->timeout; this->next = &timers[ id ]; break; } accumulated += this->timeout; last = &this->next; this = this->next; } } INT_Enable(); }
/***************************************************************************//** * @brief * Stop a DMA transfer. * * @note * The DMA will complete the current AHB burst transfer before stopping. * * @param[in] ch * DMA channel to stop. ******************************************************************************/ void LDMA_StopTransfer( int ch ) { uint32_t chMask = 1 << ch; EFM_ASSERT( ch < DMA_CHAN_COUNT ); INT_Disable(); LDMA->IEN &= ~chMask; BUS_RegMaskedClear(&LDMA->CHEN, chMask); INT_Enable(); }
/**************************************************************************//** * @brief Main function *****************************************************************************/ int main(void) { /* Chip revision alignment and errata fixes */ CHIP_Init(); /* Set the clock frequency to 11MHz so the ADC can run on the undivided HFCLK */ CMU_HFRCOBandSet(cmuHFRCOBand_11MHz); /* Configure RTC to use LFRCO as clock source */ RTC_Setup(cmuSelect_LFRCO); /* Configure ADC */ ADC_Config(); /* Start ADC sampling, adcFinished is set when sampling is finished. */ /* It is safe to do other stuff or go to EM2 while adc sampling is active. */ /* ADC sampling uses the RTC to trigger new samples. */ startAdcSampling(); /* Wait in EM2 until adc sampling is finished. */ /* Disable interrupts until flag is checked in case loop finishes after flag * check but before sleep command. Device will still wake up on any set IRQ * and any pending interrupts will be handled after interrupts are enabled * again. */ INT_Disable(); while(!adcFinished) { EMU_EnterEM2(false); INT_Enable(); INT_Disable(); } INT_Enable(); /* Finished */ while(1); }
/***************************************************************************//** * @brief * Check if a given timer is running. * * @param[in] id The id of the timer to query. * * @param[out] isRunning True if timer is running. False if not running. * Only valid if return status is ECODE_EMDRV_RTCDRV_OK. * * @return * @ref ECODE_EMDRV_RTCDRV_OK on success.@n * @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value. @n * @ref ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED if the timer is not reserved.@n * @ref ECODE_EMDRV_RTCDRV_PARAM_ERROR if an invalid isRunning pointer was * supplied. ******************************************************************************/ Ecode_t RTCDRV_IsRunning( RTCDRV_TimerID_t id, bool *isRunning ) { // Check if valid timer ID. if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) { return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID; } // Check pointer validity. if ( isRunning == NULL ) { return ECODE_EMDRV_RTCDRV_PARAM_ERROR; } INT_Disable(); // Check if timer is reserved. if ( ! timer[ id ].allocated ) { INT_Enable(); return ECODE_EMDRV_RTCDRV_TIMER_NOT_ALLOCATED; } *isRunning = timer[ id ].running; INT_Enable(); return ECODE_EMDRV_RTCDRV_OK; }
/***************************************************************************//** * @brief * Free an allocate (reserved) DMA channel. * * @param[in] channelId * The channel Id to free. * * @return * @ref ECODE_EMDRV_DMADRV_OK on success. On failure an appropriate * DMADRV @ref Ecode_t is returned. ******************************************************************************/ Ecode_t DMADRV_FreeChannel( unsigned int channelId ) { if ( !initialized ) { return ECODE_EMDRV_DMADRV_NOT_INITIALIZED; } if ( channelId > EMDRV_DMADRV_DMA_CH_COUNT ) { return ECODE_EMDRV_DMADRV_PARAM_ERROR; } INT_Disable(); if ( chTable[ channelId ].allocated ) { chTable[ channelId ].allocated = false; INT_Enable(); return ECODE_EMDRV_DMADRV_OK; } INT_Enable(); return ECODE_EMDRV_DMADRV_ALREADY_FREED; }
/***************************************************************************//** * @brief * Get wallclock time. * * @return * Seconds elapsed since RTCDRV was initialized. ******************************************************************************/ uint32_t RTCDRV_GetWallClock( void ) { uint64_t tmp; uint32_t ticks, wallClock, wallClockStartPoint; INT_Disable(); ticks = RTC_COUNTERGET(); wallClock = wallClockTime; wallClockStartPoint = wallClockInitTime; INT_Enable(); tmp = ticks - wallClockStartPoint; return wallClock + (uint32_t)TICKS_TO_SEC( tmp ); }
int main(void) { uSMARTX_Init(usmartask_table); INT_Enable(); while(1) { if(uSMARTX_Scheduler() == SYS_ERROR) break; } return 0; }
/**************************************************************************//** * @brief Main function * Main is called from __iar_program_start, see assembly startup file *****************************************************************************/ int main(void) { /* Initialize chip */ CHIP_Init(); /* Configuring clocks in the Clock Management Unit (CMU) */ setupCmu(); /* Configure DMA scatter-gather transfer */ configureDmaTransfer(); /* Starting the scatter-gather DMA operation */ DMA_ActivateScatterGather(DMA_CHANNEL_SCATTERGATHER, false, &dmaScatterCfgBlock[0], SCATTER_GATHER_TRANSFERS); /* Enter EM1 while DMA transfer is active to save power. Note that * interrupts are disabled to prevent the ISR from being triggered * after checking the transferActive flag, but before entering * sleep. If this were to happen, there would be no interrupt to wake * the core again and the MCU would be stuck in EM1. While the * core is in sleep, pending interrupts will still wake up the * core and the ISR will be triggered after interrupts are enabled * again. */ while(1) { INT_Disable(); if ( transferActive ) { EMU_EnterEM1(); } INT_Enable(); /* Exit the loop if transfer has completed */ if ( !transferActive ) { break; } } /* Cleaning up after DMA transfers */ DMA_Reset(); /* Done */ while (1); }
/***************************************************************************//** * @brief * Free timer. * * @details * Release a reserved timer. * * @param[out] id The id of the timer to release. * * @return * @ref ECODE_EMDRV_RTCDRV_OK on success.@n * @ref ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID if id has an illegal value. ******************************************************************************/ Ecode_t RTCDRV_FreeTimer( RTCDRV_TimerID_t id ) { // Check if valid timer ID. if ( id >= EMDRV_RTCDRV_NUM_TIMERS ) { return ECODE_EMDRV_RTCDRV_ILLEGAL_TIMER_ID; } INT_Disable(); timer[ id ].running = false; timer[ id ].allocated = false; INT_Enable(); return ECODE_EMDRV_RTCDRV_OK; }
/***************************************************************************//** * @brief * Check if a DMA transfer has completed. * * @param[in] ch * DMA channel to check. * * @return * True if transfer has completed, false if not. ******************************************************************************/ bool LDMA_TransferDone( int ch ) { bool retVal = false; uint32_t chMask = 1 << ch; EFM_ASSERT( ch < DMA_CHAN_COUNT ); INT_Disable(); if ( ( ( LDMA->CHEN & chMask ) == 0 ) && ( ( LDMA->CHDONE & chMask ) == chMask ) ) { retVal = true; } INT_Enable(); return retVal; }
Ecode_t COM_ReadByte(COM_Port_t port, uint8_t *dataByte) { if (checkValidPort(port)==false) { return EMBER_ERR_FATAL; } // make sure rx buffer is updated pumpRx(port); if (comhandle[port]->rxQueue->used > 0) { INT_Disable(); *dataByte = FIFO_DEQUEUE(comhandle[port]->rxQueue, comhandle[port]->rxsize); INT_Enable(); return EMBER_SUCCESS; } return EMBER_SERIAL_RX_EMPTY; }