void event_handler_on_ts_begin(void)
{
    if (!fifo_is_empty(&g_async_evt_fifo) ||
        !fifo_is_empty(&g_async_evt_fifo_ts))
    {
        NVIC_SetPendingIRQ(EVENT_HANDLER_IRQ);
    }
}
示例#2
0
void progressive_display_add_rect(struct xrdp_screen * self)
{
  int i, j;
  struct list* update_rects = self->update_rects;
  struct update_rect* urect;
  struct update_rect* fu_rect;
  struct update_rect* ur;
  struct xrdp_rect intersection;
  struct update_rect* tmp;
  struct list* l_tmp = list_create();
  l_tmp->auto_free = 1;

  bool no_inter = true;
  while (!fifo_is_empty(self->candidate_update_rects))
  {
    fu_rect = (struct update_rect*) fifo_pop(self->candidate_update_rects);
    if (update_rects->count > 0)
    {
      no_inter = true;
      for (i = update_rects->count - 1; i >= 0; i--)
      {
        urect = (struct update_rect*) list_get_item(update_rects, i);
        if (!rect_equal(&urect->rect, &fu_rect->rect))
        {
          if (rect_intersect(&urect->rect, &fu_rect->rect, &intersection))
          {
            no_inter = false;
            progressive_display_rect_union(fu_rect, urect, l_tmp);
            list_remove_item(update_rects, i);
            for (j = 0; j < l_tmp->count; j++)
            {
              ur = (struct update_rect*) list_get_item(l_tmp, j);
              tmp = (struct update_rect*) g_malloc(sizeof(struct update_rect), 0);
              g_memcpy(tmp, ur, sizeof(struct update_rect));
              fifo_push(self->candidate_update_rects, tmp);
            }
            list_clear(l_tmp);
            break;
          }
        }
        else
        {
          no_inter = false;
          urect->quality = fu_rect->quality;
          urect->quality_already_send = fu_rect->quality_already_send;
          break;
        }
      }
      if (no_inter)
      {
        list_add_progressive_display_rect(update_rects, fu_rect->rect.left, fu_rect->rect.top, fu_rect->rect.right, fu_rect->rect.bottom, fu_rect->quality, fu_rect->quality_already_send);
      }
    }
    else
    {
      list_add_progressive_display_rect(update_rects, fu_rect->rect.left, fu_rect->rect.top, fu_rect->rect.right, fu_rect->rect.bottom, fu_rect->quality, fu_rect->quality_already_send);
    }
  }
  list_delete(l_tmp);
}
示例#3
0
/***
* The thread pool has the property that all the threads will keep running until signalled to quit.
* Each thread will call pthread_exit() once it has completed execution of it's current 'task_t'.
*/
void thread_pool_join_all( thread_pool_t *pool ) {
  dna_log(DEBUG, "Joining thread pool:");
  while ( !fifo_is_empty(pool->thread_queue) ) {
    dna_mutex_lock( pool->mutex );
    int threadsAreStillRunning = 0;
    while ( (threadsAreStillRunning = fifo_any( pool->thread_queue, &thread_context_is_running)) ) {
      dna_log(DEBUG, "Some threads are still running...%i", threadsAreStillRunning);
      dna_cond_wait( pool->wait, pool->mutex );
    }
    dna_thread_context_t *context = (dna_thread_context_t*) fifo_pop( pool->thread_queue );
    if (context->runstate == RUNNING) {
      dna_log(WARN, "context is still running, placing back in the queue.");
      fifo_push( pool->thread_queue, context );
    }
    else {
      // if the context is != RUNNING, it's either SHOULD_QUIT or HAS_QUIT
      // so we have to rely on the null work we pushed earlier to clear
      // any blocks
      dna_thread_context_join( context );
      dna_thread_context_destroy(context);
    }
    dna_mutex_unlock( pool->mutex );
  }
  dna_log(DEBUG, "Thread pool joined.");
}
/*****************************************************************************
* System callbacks
*****************************************************************************/
void UART0_IRQHandler(void)
{
    /* receive all pending bytes */
    while (NRF_UART0->EVENTS_RXDRDY)
    {
        NRF_UART0->EVENTS_RXDRDY = 0;
        char_rx(NRF_UART0->RXD);
    }

    /* transmit any pending bytes */
    if (NRF_UART0->EVENTS_TXDRDY)
    {
        NRF_UART0->EVENTS_TXDRDY = 0;
        if (m_tx_len--)
        {
            NRF_UART0->TXD = *(mp_tx_ptr++);
        }
        else
        {
            NRF_UART0->TASKS_STOPTX = 1;
            if (m_serial_state != SERIAL_STATE_WAIT_FOR_QUEUE)
            {
                m_serial_state = SERIAL_STATE_IDLE;
            }

            if (!fifo_is_empty(&m_tx_fifo))
            {
                schedule_transmit();
            }
        }
    }
}
示例#5
0
void TXE_Handler()
{
  if(!fifo_is_empty(&Serial.fifo_output))
  {
    USART_WriteByte(fifo_pop(&Serial.fifo_output));
  } else {
    USART_DisableInterrupts(USART_IT_TXE);
  }
}
/**
* @brief SPI event handler, from SPI driver
*/
void spi_event_handler(spi_slave_evt_t evt)
{
    switch (evt.evt_type)
    {
        case SPI_SLAVE_BUFFERS_SET_DONE:
            if (has_pending_tx)
            {
                NRF_GPIO->OUTCLR = (1 << PIN_RDYN);
            }
            has_pending_tx = false;
            break;

        case SPI_SLAVE_XFER_DONE:
            NRF_GPIO->OUTSET = (1 << PIN_RDYN);
            nrf_gpio_pin_set(1);
            nrf_gpio_pin_clear(1);
            /* handle incoming */
            if (rx_buffer.buffer[SERIAL_LENGTH_POS] > 0)
            {
                if (fifo_push(&rx_fifo, &rx_buffer) == NRF_SUCCESS)
                {

                    /* notify ACI handler */
                    async_event_t async_evt;
                    async_evt.callback.generic = mesh_aci_command_check;
                    async_evt.type = EVENT_TYPE_GENERIC;
                    event_handler_push(&async_evt);
                }
                else
                {
                    APP_ERROR_CHECK(NRF_ERROR_NO_MEM);
                }
            }

            if (fifo_is_empty(&tx_fifo))
            {
                serial_state = SERIAL_STATE_IDLE;
                prepare_rx();
                enable_pin_listener(true);
            }
            else if (fifo_is_full(&rx_fifo))
            {
                prepare_rx();
                serial_state = SERIAL_STATE_WAIT_FOR_QUEUE;
            }
            else
            {
                do_transmit();
            }

            break;

        default:
            /* no implementation necessary */
            break;
    }
}
示例#7
0
void RunTransmission()
{
  //it is necessary to check if the buffer is not empty because an interrupt
  //can take away the byte since the previous operation
  if((~Serial.State & SERIAL_STATE_BUSY) && (!fifo_is_empty(&Serial.fifo_output)))
  {
    //USART_WriteByte(Buffer_Pop(&Serial.OutputBuffer));
    //TXE bit in SR is somehow set sot TXEI will handle the bytes in the buffer
    USART_EnableInterrupts(USART_IT_TXE);
  }
}
示例#8
0
void TC_Handler()
{
  if(!fifo_is_empty(&Serial.fifo_output))
  {
    USART_EnableInterrupts(USART_IT_TXE);
    USART_WriteByte(fifo_pop(&Serial.fifo_output));
  }
  else
  {
    Serial.State &= ~SERIAL_STATE_BUSY;
  }
}
示例#9
0
文件: fifo.c 项目: vyacht/stm32
int fifo_get(fifo_t * fifo, uint8_t * val)
{
    int ret;
    ret = !fifo_is_empty(fifo);
    if (ret) {
        *val =
            fifo->data[fifo->out & fifo->mask];
        smp_wmb();
        fifo->out++;
    }
    return ret;
}
void bootloader_abort(dfu_end_t end_reason)
{
    __LOG("ABORT...\n");
    bl_info_entry_t* p_segment_entry = bootloader_info_entry_get(BL_INFO_TYPE_SEGMENT_APP);
    switch (end_reason)
    {
        case DFU_END_SUCCESS:
        case DFU_END_ERROR_TIMEOUT:
        case DFU_END_FWID_VALID:
        case DFU_END_ERROR_MBR_CALL_FAILED:
            if (p_segment_entry && dfu_mesh_app_is_valid())
            {
                if (fifo_is_empty(&m_flash_fifo))
                {
                    interrupts_disable();

                    sd_mbr_command_t com = {SD_MBR_COMMAND_INIT_SD, };

                    uint32_t err_code = sd_mbr_command(&com);
                    APP_ERROR_CHECK(err_code);

                    err_code = sd_softdevice_vector_table_base_set(p_segment_entry->segment.start);
                    APP_ERROR_CHECK(err_code);
#ifdef DEBUG_LEDS
                    NRF_GPIO->OUTSET = (1 << 21) | (1 << 22) | (1 << 23) | (1 << 24);
#endif
                    bootloader_util_app_start(p_segment_entry->segment.start);
                }
                else
                {
                    __LOG("->Will go to app once flash is finished.\n");
                    m_go_to_app = true;
                }
            }
            else if (p_segment_entry)
            {
                __LOG("->App not valid.\n");
            }
            else
            {
                __LOG("->No segment entry found\n");
            }
            break;
        case DFU_END_ERROR_INVALID_PERSISTENT_STORAGE:
            APP_ERROR_CHECK_BOOL(false);
        default:
            __LOG(RTT_CTRL_TEXT_RED "SYSTEM RESET (reason 0x%x)\n", end_reason);
            __disable_irq();
            while(1);
            //NVIC_SystemReset();
    }
}
示例#11
0
/**
 * Remove first task in queue and decrement size
 */
static void ICACHE_FLASH_ATTR
remove_first() {

	if (my_send_state == WaitingForSend && !fifo_is_empty(msg_queue)) {
		my_send_queue_item_t *i = (my_send_queue_item_t *) fifo_pop(msg_queue);

		os_free(i->data);
		os_free(i);

		my_send_state = Idle;
	}

}
示例#12
0
文件: fifo.c 项目: jsr38/psu-firmware
/**
 * Remove element form fifo
 * @param fifo
 * @param value
 * @return FALSE - fifo is empty
 */
scpi_bool_t fifo_remove(scpi_fifo_t * fifo, int16_t * value) {
    /* FIFO empty? */
    if (fifo_is_empty(fifo)) {
        return FALSE;
    }

    if (value) {
        *value = fifo->data[fifo->rd];
    }

    fifo->rd = (fifo->rd + 1) % (fifo->size);

    return TRUE;
}
示例#13
0
文件: fifo.c 项目: jsr38/psu-firmware
/**
 * Remove last element from fifo
 * @param fifo
 * @param value
 * @return FALSE - fifo is empty
 */
scpi_bool_t fifo_remove_last(scpi_fifo_t * fifo, int16_t * value) {
    /* FIFO empty? */
    if (fifo_is_empty(fifo)) {
        return FALSE;
    }

    fifo->wr = (fifo->wr + fifo->size - 1) % (fifo->size);

    if (value) {
        *value = fifo->data[fifo->wr];
    }

    return TRUE;
}
示例#14
0
文件: fifo.c 项目: Blackclaws/tinyusb
bool fifo_read(fifo_t* f, uint8_t *data)
{
  if (fifo_is_empty(f))
    return false;

  mutex_lock(f);

  *data = f->buf[f->rd_ptr];
  f->rd_ptr = (f->rd_ptr + 1) % f->size;
  f->len--;

  mutex_unlock(f);

  return true;
}
示例#15
0
文件: main.c 项目: dwerner/libmelon
// test-helper: empty the fifo and see what we have in it
void fifo_check() {
  dna_log(DEBUG, "emptying result fifo...");
  int ctr = 0;
  while( !fifo_is_empty(fifo) )  {
    void *val = fifo_pop( fifo );
    if (val) {
      message_t *msg = (message_t *) val;
      if (msg) {
        free(msg);
      }
      ctr++;
    }
  }
  dna_log(INFO, "Counted %i elements popped from value queue", ctr);
}
示例#16
0
/***
 * Send data if in Idle state
 */
static void ICACHE_FLASH_ATTR
my_sent_next() {

	if (my_send_state == Idle && !fifo_is_empty(msg_queue)) {

		my_send_state = WaitingForSend;
		my_send_queue_item_t *i = (my_send_queue_item_t *) fifo_first(msg_queue);

		// when the connection is closed do not send the data
		if (i->l->free) {
			remove_first();
			my_sent_next();
		} else {
			espconn_sent(i->l->pCon, i->data, i->length);
		}
	}

}
示例#17
0
/**
* @brief Called when master requests send, or we want to notify master
*/
static void do_transmit(void)
{
    uint8_t* tx_ptr = &dummy_data;
    uint8_t tx_len = 0;
    uint32_t error_code;

    serial_state = SERIAL_STATE_TRANSMIT;

    /* don't want GPIOTE to interrupt again before after packet is
    successfully transmitted. */
    enable_pin_listener(false);

    bool ordered_buffer = false;

    if (!fifo_is_empty(&tx_fifo))
    {
        if (fifo_pop(&tx_fifo, &tx_buffer) == NRF_SUCCESS)
        {
            tx_len = tx_buffer.buffer[0] + 2;
            tx_ptr = (uint8_t*) &tx_buffer;
            memset(rx_buffer.buffer, 0, SERIAL_DATA_MAX_LEN);
            error_code = spi_slave_buffers_set(tx_ptr,
                                              rx_buffer.buffer,
                                              tx_len,
                                              sizeof(rx_buffer));
            APP_ERROR_CHECK(error_code);
            ordered_buffer = true;
            has_pending_tx = true;
        }
    }
    if (!ordered_buffer)
    {
        /* don't need to wait for SPIS mutex */
        NRF_GPIO->OUTCLR = (1 << PIN_RDYN);
    }

    nrf_gpio_pin_set(0);
    nrf_gpio_pin_clear(0);

    /* wait for SPI driver to finish buffer set operation */
}
示例#18
0
文件: pmc_sbi.c 项目: Xilinx/qemu
static void ss_stream_notify(void *opaque)
{
    SlaveBootInt *s = SBI(opaque);
    uint32_t num = 0;
    uint8_t *data;

    while (stream_can_push(s->tx_dev, ss_stream_notify, s)) {
        if (fifo_is_empty(&s->fifo)) {
            break;
        }
        /* num is equal to number of bytes read as its a fifo of width 1byte.
         * the same dosent holds good if width is grater than 1 byte
         */
        data = (uint8_t *) fifo_pop_buf(&s->fifo,
                        4, &num);

        stream_push(s->tx_dev, data, num, 0);
    }
    ss_update_busy_line(s);
    sbi_update_irq(s);
}
示例#19
0
void thread_pool_destroy( thread_pool_t *pool ) {
  dna_log(DEBUG, "Inside thread_pool_destroy()");
  if ( pool ) {
    dna_log(DEBUG, "Telling threads to exit...");
    thread_pool_join_all(pool);
    dna_log(DEBUG, "Destroying execution context fifo...");
    fifo_destroy( pool->thread_queue );
    pool->thread_queue = NULL;
    dna_log(DEBUG, "Destroying tasks in fifo...");
    while ( !fifo_is_empty( pool->tasks ) ) {
      task_t *task = (task_t*) fifo_pop( pool->tasks );
      task_destroy( task );
    }
    fifo_destroy( pool->tasks );
    pool->tasks = NULL;
    dna_log(DEBUG, "Freeing thread context pool \"%s\".", pool->name);
    dna_mutex_destroy( pool->mutex );
    dna_cond_destroy( pool->wait );
    free(pool->mutex);
    free(pool->wait);
    free( pool );
  }
}
static inline bool all_operations_ended(void)
{
    return (fifo_is_empty(&m_flash_op_fifo) && (m_operations_reported == m_operation_count));
}
/** Interrupt handling Flash operations. */
void FLASH_HANDLER_IRQHandler(void)
{
    flash_queue_entry_t flash_entry;
    uint32_t op_count = 0;
    while (fifo_pop(&m_flash_fifo, &flash_entry) == NRF_SUCCESS)
    {
        op_count++;
        bl_cmd_t rsp_cmd;
        if (flash_entry.type == FLASH_OP_TYPE_WRITE)
        {
            APP_ERROR_CHECK_BOOL(IS_WORD_ALIGNED(flash_entry.op.write.start_addr));
            APP_ERROR_CHECK_BOOL(IS_WORD_ALIGNED(flash_entry.op.write.length));
            APP_ERROR_CHECK_BOOL(IS_WORD_ALIGNED(flash_entry.op.write.p_data));
            __LOG("WRITING to 0x%x.(len %d)\n", flash_entry.op.write.start_addr, flash_entry.op.write.length);
            if (flash_entry.op.write.start_addr >= 0x20000000)
            {
                uint8_t* p_dst = ((uint8_t*) flash_entry.op.write.start_addr);
                for (uint32_t i = 0; i < flash_entry.op.write.length; ++i, p_dst++)
                {
                    *p_dst = (*p_dst & flash_entry.op.write.p_data[i]);
                }
            }
            else
            {
                nrf_flash_store((uint32_t*) flash_entry.op.write.start_addr,
                                            flash_entry.op.write.p_data,
                                            flash_entry.op.write.length, 0);
            }

            rsp_cmd.type                      = BL_CMD_TYPE_FLASH_WRITE_COMPLETE;
            rsp_cmd.params.flash.write.p_data = flash_entry.op.write.p_data;
        }
        else
        {
            __LOG("ERASING 0x%x.\n", flash_entry.op.erase.start_addr);
            if (flash_entry.op.erase.start_addr >= 0x20000000)
            {
                memset((uint32_t*) flash_entry.op.erase.start_addr, 0xFF, flash_entry.op.erase.length);
            }
            else
            {
                nrf_flash_erase((uint32_t*) flash_entry.op.erase.start_addr,
                                            flash_entry.op.erase.length);
            }
            rsp_cmd.type                      = BL_CMD_TYPE_FLASH_ERASE_COMPLETE;
            rsp_cmd.params.flash.erase.p_dest = (uint32_t*) flash_entry.op.erase.start_addr;
        }
        bl_cmd_handler(&rsp_cmd);
    }

    if (op_count > 0)
    {
        bl_cmd_t idle_cmd;
        idle_cmd.type = BL_CMD_TYPE_FLASH_ALL_COMPLETE;
        bl_cmd_handler(&idle_cmd);
    }
    if (fifo_is_empty(&m_flash_fifo) && m_go_to_app)
    {
        bl_info_entry_t* p_segment_entry = bootloader_info_entry_get(BL_INFO_TYPE_SEGMENT_APP);
        bootloader_util_app_start(p_segment_entry->segment.start);
    }
}
示例#22
0
int main(void)
{
	// Configure CPU and peripherals clock
	xmega_set_cpu_clock_to_32MHz();
	
	// Enable interrupts
	PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
	
	// Power management - configure sleep mode to IDLE
	set_sleep_mode(SLEEP_SMODE_IDLE_gc);
	// Enable sleep mode
	sleep_enable();

#ifdef MMSN_DEBUG	
	// Initialize serial communication terminal
	//usartCommTerminalInit();
	
	// Configure and initialize communication bus usart
	xmega_usart_configure();
	
	/* RS-485 PHYSICAL DEVICE CONFIGURATION */
	// Initialize GPIO related to RS-485 interface
	rs485_driver_gpio_initialize();
	// Initially go LOW to enable receiver and start listening
	rs485_driver_enable();
	
	/* USART INTERRUPTS CONFIGURATION - RECEIVING */
	// Turn on USART RXC interrupt
	xmega_set_usart_rx_interrupt_level(&USART_COMMUNICATION_BUS, USART_RXCINTLVL_HI_gc);
	
	// Turn off TXC and DRE interrupts
	xmega_set_usart_tx_interrupt_level(&USART_COMMUNICATION_BUS, USART_TXCINTLVL_OFF_gc);
	xmega_set_usart_dre_interrupt_level(&USART_COMMUNICATION_BUS, USART_DREINTLVL_OFF_gc);
	
	// Redirect stream to standard output
	stdout = &mystdout;
	
	/* Print out welcome message */
	//static const char WelcomeMessage[] PROGMEM = "Multi-Master Serial Network Manager ver 1.0";
	//printf("%S\n", WelcomeMessage);
	printf_P(PSTR("\nMulti-Master Serial Network Manager ver 1.0\n"));
	//printf("Multi-Master Serial Network Manager ver 1.0\n");
#endif
	
	// Calculate CRC-16 value based on the random Internal SRAM memory content.
	// Move by 0x400 from the beginning to omit memory area related to global variables section.
	// Take 20 consecutive SRAM bytes for CRC-16 calculation.
	uint16_t u16RandomValue = xmega_calculate_checksum_crc16((uint8_t *)(INTERNAL_SRAM_START + 1200), 20);
	// Pseudo-random number generator seeding with previously obtain value
	srand(u16RandomValue);
	
#ifdef MMSN_DEBUG
	printf("rnd = %u\n", u16RandomValue);
#endif	
	
	// Read XMEGA device serial number
	nvm_read_device_serial(&xmegaSerialNumber);

	// Read configuration data from EEPROM
	xmega_read_configuration_data();

	// Check if logical address was already assigned
	if (true == _isLogicalNetworkAddrAssigned(&ConfigurationData.u8LogicalNetworkAddr))
	{
		// Logical Network Address was already assigned.
		g_DeviceConfigStatus = eLogicalAddrAssigned;
		
		// Calculate Collision Avoidance (back-off/busy line) timer period value.
		g_u16CollisionAvoidancePeriod = (ConfigurationData.u8LogicalNetworkAddr * TIMER_COLLISION_AVOIDANCE_520us_VALUE) +
									   TIMER_COLLISION_AVOIDANCE_32us_VALUE;
#ifdef MMSN_DEBUG
		printf("LNA_CA = %d\n", g_u16CollisionAvoidancePeriod);
#endif
	}
	else
	{
		// Logical Network Address was NOT assigned.
		g_DeviceConfigStatus = eLogicalAddrNotAssigned;
		
		// Calculate Collision Avoidance (back-off/busy line) timer period using random value.
		g_u16CollisionAvoidancePeriod = (xmega_generate_random_logical_network_address() * TIMER_COLLISION_AVOIDANCE_520us_VALUE) +
		TIMER_COLLISION_AVOIDANCE_32us_VALUE;

#ifdef MMSN_DEBUG
		printf("RND_CA = %d\n", g_u16CollisionAvoidancePeriod);
#endif		
	}
	
	/************************************************************************/
	/* TIMERS CONFIGURATION                                                 */
	/************************************************************************/
	
	// No response timer - configure but do not run
	xmega_timer_config(&TIMER_NO_RESPONSE, TC_CLKSEL_OFF_gc, TIMER_NO_RESPONSE_PERIOD);
	
	// Collision Avoidance timer - configure but do not run
	xmega_timer_config(&TIMER_COLLISION_AVOIDANCE, TC_CLKSEL_OFF_gc, g_u16CollisionAvoidancePeriod);
	
	// Heartbeat timer - configure but do not run
	xmega_timer_config(&TIMER_HEARTBEAT, TC_CLKSEL_OFF_gc, TIMER_HEARTBEAT_PERIOD);
	
	// Force the state of the SREG register on exit, disabling the Global Interrupt Status flag bit.
	/* ATOMIC_BLOCK(NONATOMIC_FORCEOFF)
	{
		// Clear busy line timeout event
		FLAG_CLEAR(gSystemEvents, EVENT_IRQ_COLLISION_AVOIDANCE_TIMEOUT_bm);
	}
	
	// Turn busy line timer off
	xmega_tc_select_clock_source(&TIMER_COLLISION_AVOIDANCE, TC_CLKSEL_OFF_gc); */
	
	/* Initialize event queue */
	fifo_init(&eventQueue_desc, &EventQueue[0], EVENT_FIFO_BUFFER_SIZE);
	
	/************************************************************************/
	/* Initialize Multi-Master Serial Network State Machine                 */
	/************************************************************************/
	// SM_stateTable[eSM_Initialize]();
	//mmsn_InitializeStateMachine(&mmsnFSM);
	
	// Initialize global storage for data sending
	_sendData_FrameBuffer_Init(&gStorage_SendData);
	
	// Start heartbeat timer
	xmega_tc_select_clock_source(&TIMER_HEARTBEAT, TC_CLKSEL_DIV64_gc);
	
	xmega_set_usart_rx_interrupt_level(&USART_COMMUNICATION_BUS, USART_RXCINTLVL_HI_gc);
	
	// Turn on global interrupts
	sei();
	
	/************************************************************************/
	/* Start infinite main loop, go to sleep and wait for interruption      */
	/************************************************************************/
	for(;;)
    {
		// Force the state of the SREG register on exit, enabling the Global Interrupt Status flag bit.
        ATOMIC_BLOCK(ATOMIC_FORCEON)
		{
			// Atomic interrupt safe read of global variable storing event flags
			u16EventFlags = gSystemEvents;
		};
		
        while (u16EventFlags)
        {
	        // Note: Each handler will clear the relevant bit in global variable gSystemEvents
			// Corresponding event flag will be cleared in FSM handler		

			// Heartbeat timer interrupt fired up
			if (u16EventFlags & SYSEV_HEARTBEAT_TIMEOUT_bm)
			{
				if (gHeartBeatCounter > 5000)
				{
					// create a message
					gStorage_SendData.u8DataSize = 7;
					gStorage_SendData.u8IsResponseNeeded = true;
					gStorage_SendData.u8SendDataBuffer[0] = 1;
					gStorage_SendData.u8SendDataBuffer[1] = 3;
					gStorage_SendData.u8SendDataBuffer[2] = 5;
					gStorage_SendData.u8SendDataBuffer[3] = 7;
					gStorage_SendData.u8SendDataBuffer[4] = 9;
					gStorage_SendData.u8SendDataBuffer[5] = 11;
					gStorage_SendData.u8SendDataBuffer[6] = 33;
					
					// add event to queue
					ADD_EVENT_TO_QUEUE(&eventQueue_desc, MMSN_SEND_DATA_EVENT);
					
					// reset counter
					gHeartBeatCounter = 0;
					
					// Stop heartbeat timer
					xmega_tc_select_clock_source(&TIMER_HEARTBEAT, TC_CLKSEL_OFF_gc);
				}
				
				sys_HeartbeatTimeout_Handler();
			};
			
			// Collision Avoidance timer interrupt fired up
			if (u16EventFlags & SYSEV_COLLISION_AVOIDANCE_TIMEOUT_bm)
			{
				sysev_CollisionAvoidanceTimeout_Handler();
			};
			
			// No response timer interrupt fired up
			if (u16EventFlags & SYSEV_NO_RESPONSE_TIMEOUT_bm)
			{
				sysev_NoResponseTimeout_Handler();
			};
			
			// Receive Complete (RXC) interrupt fired up
			if (u16EventFlags & SYSEV_RECEIVE_COMPLETE_bm)
			{
				sysev_ReceiveComplete_Handler();
			};
			
			// Data Register Empty (DRE) interrupt fired up
			if (u16EventFlags & SYSEV_DATA_REGISTER_EMPTY_bm)
			{
				sysev_DataRegisterEmpty_Handler();
			};
			
			// Transmit Complete (TXC) interrupt fired up
			if (u16EventFlags & SYSEV_TRANSMIT_COMPLETE_bm)
			{
				sysev_TransmitComplete_Handler();
			};
			
			// Dispatch events from the MMSN FSM queue
			while(!fifo_is_empty(&eventQueue_desc))
			{
				// Get event from the queue
				uint8_t currEvent = fifo_pull_uint8_nocheck(&eventQueue_desc);
				
				// Call corresponding FSM event handler
				if (mmsnFSMActionTable[mmsnFSM.CurrentState][currEvent])
				{
					mmsnFSMActionTable[mmsnFSM.CurrentState][currEvent](&mmsnFSM, currEvent, &g_u8GlobalArgument);
				}
			};
			
			// Read the system event flag again after handlers return
			ATOMIC_BLOCK(ATOMIC_FORCEON)
			{
				// Atomic interrupt safe read of global variable storing event flags
				u16EventFlags = gSystemEvents;
			}
        }	// while(...)
        
        // Read the event register again without allowing any new interrupts
		cli();
		
        if (0 == gSystemEvents)
        {
			sei();
			
	        // Go to sleep, everything is handled by interrupts.
	        // An interrupt will cause a wake up and run the while loop
	        sleep_cpu();
        };
        
		// Set Global Interrupt Status flag
        sei();
    };
};
bool mesh_flash_in_progress(void)
{
    return (!fifo_is_empty(&m_flash_op_fifo) || m_curr_op.type != FLASH_OP_TYPE_NONE);
}