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); } }
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); }
/*** * 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(); } } } }
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; } }
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); } }
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; } }
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(); } }
/** * 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; } }
/** * 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; }
/** * 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; }
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; }
// 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); }
/*** * 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); } } }
/** * @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 */ }
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); }
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); } }
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); }