示例#1
0
static int submenu_backuponevolume(const Volume* volume)
{
	char**				headers = NULL;		// UI menu headers
	char**	 			items = NULL;		// UI menu items
	char 				temp[256];			// Temporary string space
	cmd_backup_method 	method;				// Selected backup method
	int 				compress;			// Flag to use compression or not
	int 				selection;			// Selected menu item
	int 				nav;				// Menu navigation code

	// Allocate a standard header
	headers = alloc_standard_header(SUBHEADER_BACKUPVOLUMES);
	if(headers == NULL) { LOGE("submenu_backuponevolume: Cannot allocate menu headers"); return NAVIGATE_ERROR; }
	
	// Allocate an empty menu list that we will append all the backup methods to
	items = alloc_menu_list(NULL);
	if(items == NULL) {
		
		LOGE("submenu_backuponevolume: Cannot allocate menu items");
		free_menu_list(headers);
		return NAVIGATE_ERROR;
	}
	
	// Provide the user with a choice of what backup imaging method to use
	sprintf(temp, "- Backup %s [ext4 image]", volume->name);
	items = append_menu_list(items, temp);
	
	sprintf(temp, "- Backup %s [ext4 sparse image]", volume->name);
	items = append_menu_list(items, temp);
	
	sprintf(temp, "- Backup %s [raw dump]", volume->name);
	items = append_menu_list(items, temp);
	
	sprintf(temp, "- Backup %s [yaffs2 image]", volume->name);
	items = append_menu_list(items, temp);

	// Navigate the generated menu
	nav = navigate_menu(headers, items, &selection);
	while(nav == NAVIGATE_SELECT) {
		
		switch(selection) {
			
			case 0: cmd_backup_volume(volume, ext4, g_backup_compression); break;
			case 1: cmd_backup_volume(volume, ext4_sparse, g_backup_compression); break;
			case 2: cmd_backup_volume(volume, dump, g_backup_compression); break;
			case 3: cmd_backup_volume(volume, yaffs2, g_backup_compression); break;
		}
		
		nav = NAVIGATE_BACK;
	}

	free_menu_list(items);				// Release the string array
	free_menu_list(headers);			// Release the string array
	
	return nav;							// Return navigation code
}
示例#2
0
static int submenu_unmountvolumes(void)
{
	char**				headers = NULL;		// UI menu headers
	char**	 			items = NULL;		// UI menu items
	int 				selection;			// Selected menu item
	const Volume*		selvol;				// Selected Volume item
	int 				nav;				// Menu navigation code
	
	// Allocate a standard header
	headers = alloc_standard_header(SUBHEADER_UNMOUNTVOLUMES);
	if(headers == NULL) { LOGE("submenu_unmountvolumes: Cannot allocate menu headers"); return NAVIGATE_ERROR; }
	
	// Create the list of volume menu items for this operation
	CREATE_VOLMENU_FLAGS flags = { "Unmount", NULL, 0 };
	items = create_volume_menuitems(&flags);
	if(items == NULL) {
		
		LOGE("submenu_unmountvolumes: Cannot allocate menu items");
		free_menu_list(headers);
		return NAVIGATE_ERROR;
	}
	
	// Navigate the generated menu
	nav = navigate_menu(headers, items, &selection);
	while(nav == NAVIGATE_SELECT) {
		
		// Convert the selection code into a Volume pointer we can use
		selvol = select_volume_menuitem(selection, &flags);
		if(selvol != NULL) cmd_unmount_volume(selvol);

		if(nav == NAVIGATE_HOME) break;
		nav = navigate_menu(headers, items, &selection);
	}
	
	free_menu_list(items);				// Release the string array
	free_menu_list(headers);			// Release the string array
	
	return nav;							// Return navigation code
}
示例#3
0
static int submenu_restoreonevolume_confirm(const Volume* volume, const char* imgfile)
{
	char**				headers = NULL;		// UI menu headers
	char**	 			items = NULL;		// UI menu items
	char 				temp[256];			// Temporary string space
	int 				selection;			// Selected menu item
	int 				result;				// Result from function call
	int 				nav;				// Menu navigation code
	
	// Allocate a standard header
	headers = alloc_standard_header(SUBHEADER_RESTOREVOLUMES);
	if(headers == NULL) { LOGE("submenu_restoreonevolume_confirm: Cannot allocate menu headers\n"); return NAVIGATE_ERROR; }
	
	// Provide a warning message at the end of the header list
	sprintf(temp, "WARNING: All data on volume %s will be", volume->name);
	headers = append_menu_list(headers, temp);
	headers = append_menu_list(headers, "replaced by the backup image. Continue?");
	headers = append_menu_list(headers, "");
	
	// Format the YES option string
	sprintf(temp, "- Yes -- Restore %s", volume->name);

	// Allocate the confirmation menu
	items = alloc_menu_list("- No",
							"- No",
							"- No",
							"- No",
							temp,			// <--- 4
							"- No",
							"- No",
							"- No",
							"- No",
							NULL);
	
	if(items == NULL) {
		
		LOGE("submenu_restoreonevolume_confirm: Cannot allocate menu items");
		free_menu_list(headers);
		return NAVIGATE_ERROR;
	}
	
	// If the user selected YES, go ahead and format the volume
	nav = navigate_menu(headers, items, &selection);
	if((nav == NAVIGATE_SELECT) && (selection == 4)) cmd_restore_volume(imgfile, volume);

	free_menu_list(items);				// Release the string array
	free_menu_list(headers);			// Release the string array
	
	return nav;							// Return navigation code
}
示例#4
0
static int submenu_formatonevolume(const Volume* volume)
{
	char**				headers = NULL;		// UI menu headers
	char**	 			items = NULL;		// UI menu items
	char 				temp[256];			// Temporary string space
	int 				selection;			// Selected menu item
	int 				nav;				// Menu navigation code

	// If there is no secondary filesystem listed in the FSTAB for this volume,
	// jump right into confirmation ...
	if(volume->fs_type2 == NULL) 
		return submenu_formatonevolume_confirm(volume, volume->fs_type);

	// Allocate a standard header
	headers = alloc_standard_header(SUBHEADER_FORMATVOLUMES);
	if(headers == NULL) { LOGE("submenu_formatonevolume: Cannot allocate menu headers"); return NAVIGATE_ERROR; }
	
	// Allocate an empty menu list that we will append all the volumes to
	items = alloc_menu_list(NULL);
	if(items == NULL) {
		
		LOGE("submenu_formatonevolume: Cannot allocate menu items");
		free_menu_list(headers);
		return NAVIGATE_ERROR;
	}
	
	// Provide the user with a choice of formatting with either the primary or secondary
	// file system (or getting out of the operation altogether)
	sprintf(temp, "- Format %s [%s]", volume->name, volume->fs_type);
	items = append_menu_list(items, temp);
	
	sprintf(temp, "- Format %s [%s]", volume->name, volume->fs_type2);
	items = append_menu_list(items, temp);
	
	// Determine which option the user chose and continue on into confirmation
	nav = navigate_menu(headers, items, &selection);
	if(nav == NAVIGATE_SELECT) {
		
		switch(selection) {
		
			case 0 : nav = submenu_formatonevolume_confirm(volume, volume->fs_type); break;
			case 1 : nav = submenu_formatonevolume_confirm(volume, volume->fs_type2); break;
		}
	}
	
	free_menu_list(items);				// Release the string array
	free_menu_list(headers);			// Release the string array
	
	return nav;							// Return navigation code
}
示例#5
0
static int submenu_convertonevolume(const Volume* volume)
{
	char**				headers = NULL;		// UI menu headers
	char**	 			items = NULL;		// UI menu items
	char 				temp[256];			// Temporary string space
	cmd_backup_method 	method;				// Selected backup method
	int 				selection;			// Selected menu item
	int 				nav;				// Menu navigation code

	// Allocate a standard header
	headers = alloc_standard_header(SUBHEADER_CONVERTVOLUMES);
	if(headers == NULL) { LOGE("submenu_convertonevolume: Cannot allocate menu headers"); return NAVIGATE_ERROR; }
	
	// Allocate an empty menu list that we will append all the backup methods to
	items = alloc_menu_list(NULL);
	if(items == NULL) {
		
		LOGE("submenu_convertonevolume: Cannot allocate menu items");
		free_menu_list(headers);
		return NAVIGATE_ERROR;
	}
	
	// Provide the user with a choice of what backup imaging method to use
	sprintf(temp, "- Convert %s [%s]", volume->name, volume->fs_type);
	items = append_menu_list(items, temp);
	
	sprintf(temp, "- Convert %s [%s]", volume->name, volume->fs_type2);
	items = append_menu_list(items, temp);
	
	// Navigate the generated menu
	nav = navigate_menu(headers, items, &selection);
	while(nav == NAVIGATE_SELECT) {
		
		switch(selection) {
			
			case 0: cmd_convert_volume(volume, volume->fs_type); break;
			case 1: cmd_convert_volume(volume, volume->fs_type2); break;
		}
		
		nav = NAVIGATE_BACK;
	}

	free_menu_list(items);				// Release the string array
	free_menu_list(headers);			// Release the string array
	
	return nav;							// Return navigation code
}
示例#6
0
void loc_rsp_get_param(void* rsp)
{
    rvn_loc_cmd_radio_connect_t cmd;
    uint32_t blcc;
    rvn_loc_rsp_get_param_t* rsp_param = (rvn_loc_rsp_get_param_t*)rsp;
    FMENU_item_flash_t* current_menu_entry = FMENU_GetCurrentItem(&MENU_menuHandle);
    FMENU_item_flash_t* startup_menu_entry;
    menu_action_t menu_action = MENU_ACTION_REFRESH;
    
    switch (avrraven.status.state) {
    case STATE_RADIO_GET_PARAM:
        lcd_num_puthex(*(uint16_t*)&rsp_param->data[0], LCD_NUM_PADDING_ZERO);
        avrraven.status.state = STATE_IDLE;
    
        SIPC_ACK_PACKET();
        break;
    case STATE_RADIO_GET_ADDRESS_WAIT_RESPONSE:
        avrraven.status.ntwk_address = *(uint16_t*)&rsp_param->data[0];
        navigate_menu(current_menu_entry, current_menu_entry, menu_action);
        led_status_set(LED_OFF);
        avrraven.status.state = STATE_IDLE;
    
        SIPC_ACK_PACKET();
        break;
    case STATE_M1284P_RESTART_GET_REV:
        // Store M1284P FW revisions
        avrraven.status.m1284p_app_rev = rsp_param->data[0];
        avrraven.status.m1284p_app_rev |= rsp_param->data[1] << 8;
        avrraven.status.m1284p_bl_rev  = rsp_param->data[2];
        avrraven.status.m1284p_bl_rev  |= rsp_param->data[3] << 8;
    
        SIPC_ACK_PACKET();
        
        // Read bootloader communication channel in EEPROM
        BLCC_READ(blcc);
        if (blcc == BLCC_FW_UPGRADE_COMPLETE) {
            // Enable radio
            cmd.id = RVN_LOC_CMD_RADIO_CONNECT;
            cmd.channel = avrraven.user_config.channel;
            cmd.pan_id = avrraven.user_config.panid;
            sipc_send_frame(sizeof(rvn_loc_cmd_radio_connect_t), (uint8_t *)&cmd);
            lcd_puts_P("JOINING NETWORK");
            led_status_set(LED_SOFT_BLINK);
            avrraven.status.state = STATE_FW_WRITE_COMPLETE_WAIT_RADIO;
        } else {
            // Navigate to startup menu
            startup_menu_entry = FMENU_GoToRootItem(&MENU_menuHandle);
            navigate_menu(startup_menu_entry, startup_menu_entry, menu_action);
            
            // If auto join is enabled, try to join network
            if (avrraven.user_config.join_auto == true) {
                // Enable radio
                cmd.id = RVN_LOC_CMD_RADIO_CONNECT;
                cmd.channel = avrraven.user_config.channel;
                cmd.pan_id = avrraven.user_config.panid;
                sipc_send_frame(sizeof(rvn_loc_cmd_radio_connect_t), (uint8_t *)&cmd);
                lcd_puts_P("JOINING NETWORK");
                led_status_set(LED_SOFT_BLINK);
                lcd_num_clr_all();
                avrraven.status.state = STATE_RADIO_CONNECTING;
            } else {
                avrraven.status.state = STATE_IDLE;
            }
        }
        break;
    default:
        // Param responses in unknown state is ignored. Impossible to know what to do with the data
        break;
    }
}
示例#7
0
int menu_volumemanagement(void)
{
	char**				headers = NULL;		// UI menu headers
	char**	 			items = NULL;		// UI menu items
	int 				selection;			// Selected menu item
	int 				nav;				// Return navigation code
	
	// Allocate a standard header
	headers = alloc_standard_header(SUBHEADER_VOLUMEMGMT);
	if(headers == NULL) { LOGE("menu_volumemanagement: Cannot allocate menu headers"); return NAVIGATE_ERROR; }
	
	// Allocate the menu item list
	items = alloc_menu_list(
		"- Mount Volumes",
		"- Unmount Volumes",
		"- Backup Volumes",
		"- Restore Volumes",
		"- Convert Volumes",
		"- Format Volumes",
		NULL);
	
	if(items == NULL) {
		LOGE("menu_volumemanagement: Cannot allocate menu items");
		free_menu_list(headers);
		return NAVIGATE_ERROR;
	}
	
	// Navigate the generated menu
	nav = navigate_menu(headers, items, &selection);
	while(nav == NAVIGATE_SELECT) {

		switch(selection) {
			
			// MOUNT VOLUMES
			case 0: nav = submenu_mountvolumes(); break;
				
			// UNMOUNT VOLUMES
			case 1: nav = submenu_unmountvolumes(); break;
			
			// BACKUP VOLUMES
			case 2: nav = submenu_backupvolumes(); break;
				
			// RESTORE VOLUMES
			case 3: nav = submenu_restorevolumes(); break;
			
			// CONVERT VOLUMES
			case 4: nav = submenu_convertvolumes(); break;

			// FORMAT VOLUMES
			case 5: nav = submenu_formatvolumes(); break;
		}
		
		// NAVIGATE_HOME after a command breaks the loop so that
		// the menu system will unwind all the way back to the main menu
		if(nav == NAVIGATE_HOME) break;
		else nav = navigate_menu(headers, items, &selection);
	}
	
	free_menu_list(items);				// Release the string array
	free_menu_list(headers);			// Release the string array
	
	return nav;							// Return navigation code
}
示例#8
0
void int_evt_key(void* evt)
{
    key_state_t key_state = *(key_state_t*)evt;
    FMENU_item_flash_t* current_menu_entry = FMENU_GetCurrentItem(&MENU_menuHandle);
    FMENU_item_flash_t* new_menu_entry = current_menu_entry;
    menu_action_t menu_action = MENU_ACTION_ENTER;
    int int_temp;
    static uint8_t file_name[SFS_MAX_FILENAME_BUFFER_SIZE];
    unsigned char search_string[SFS_MAX_FILENAME_BUFFER_SIZE];
    lcd_config_t config;
    static key_state_t auto_key_state;
    static bool auto_key_wait = true;
    static bool auto_key_registered = false;
    static asy_tmr_t auto_key_timer = ASY_TMR_NO_TIMER;
    
    // Navigate to next avrraven.status.state
    switch (key_state){
    case KEY_UP:
        switch (avrraven.status.state) {
        case STATE_IDLE:
            new_menu_entry = FMENU_NavigateUp(&MENU_menuHandle);
            break;
        case STATE_CONFIG_DEBUG_ENABLE:
            lcd_puts_P("ENABLE");
            avrraven.user_config.debug_enable = true;
            break;
        case STATE_CONFIG_TXTPREV_ENABLE:
            lcd_puts_P("ENABLE");
            avrraven.user_config.txtmsg_preview = true;
            break;
        case STATE_CONFIG_FW_UPGRADE:
            lcd_puts_P("AUTO");
            avrraven.user_config.fw_upgr_auto = true;
            break;
        case STATE_CONFIG_CONNECT:
            lcd_puts_P("AUTO");
            avrraven.user_config.join_auto = true;
            break;
        case STATE_CONFIG_IMG_RCV:
            lcd_puts_P("AUTO");
            avrraven.user_config.fw_rcv_auto = true;
            break;
        case STATE_CONFIG_NAME:
        case STATE_MAIL_COMPOSE:
            txtedit_event(TXTEDIT_KEY_UP);
            break;
        case STATE_CONFIG_LCD_CONTRAST:
            lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_SPACE);
            config = lcd_config_get();
            config.contrast = numedit_buffer;
            lcd_config_set(config);
            break;
        case STATE_CONFIG_CLOCK_MIN:
            {
                timendate_clk_t set_time;
                timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // hours from current clock
                int clk = set_time.hour*100 + numedit_event(NUMEDIT_KEY_UP); // minutes from current editing
                lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_CONFIG_CLOCK_HOUR:
            {
                timendate_clk_t set_time;
                timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // minutes from current clock
                int clk = numedit_event(NUMEDIT_KEY_UP)*100 + set_time.min; // hours from current editing
                lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_CONFIG_LCD_SCROLLING:
            lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_SPACE);
            
            // Update LCD scrolling settings
            config = lcd_config_get();
            config.scrolling = (lcd_scrolling_t)numedit_value_get();
            lcd_config_set(config);
            break;
        case STATE_CONFIG_RADIO_CHANNEL:
            lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_SPACE);
            break;
        case STATE_CONFIG_RADIO_PANID:
        case STATE_MAIL_COMPOSE_ADDRESS_SET:
            lcd_num_puthex(numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_ZERO);
            break;
        case STATE_CONFIG_UNIT_TEMP:
            avrraven.user_config.unit.temp = TEMP_UNIT_CELCIUS;
            lcd_symbol_clr(LCD_SYMBOL_F);
            lcd_symbol_set(LCD_SYMBOL_C);
            break;
        case STATE_CONFIG_UNIT_CLOCK:
            avrraven.user_config.unit.clock = TIME_CLOCK_UNIT_24;
            if (avrraven.user_config.unit.clock == TIME_CLOCK_UNIT_24) {
                lcd_symbol_clr(LCD_SYMBOL_AM);
                lcd_symbol_clr(LCD_SYMBOL_PM);
                lcd_num_puthex(0x2400, LCD_NUM_PADDING_ZERO);
            } else {
                lcd_symbol_set(LCD_SYMBOL_AM);
                lcd_symbol_set(LCD_SYMBOL_PM);
                lcd_num_puthex(0x1200, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_MAIL_READ:
            mbox_mail_get(&current_mail, MBOX_GET_NEXT);
            if (current_mail != NULL) {
                int_temp = current_mail->size;
                lcd_puta(current_mail->data, int_temp);
                lcd_num_puthex(current_mail->address, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_FW_WAIT_USER_CONFIRMATION:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_AUDIO_FILE_SELECT:
            strncpy_P((char*)search_string, AUDIO_FILE_TYPE, AUDIO_FILE_TYPE_SIZE);
            if (avrraven.status.batt_low == false) {
                sfs_fget(search_string, file_name, SFS_FGET_REV);
                lcd_puts((const char*)file_name);
            } else {
                lcd_puts_P("ERROR");
            }
            break;
        case STATE_STORAGE_FILE_LIST:
            strncpy_P((char*)search_string, "*.*", 4);
            if (avrraven.status.batt_low == false) {
                sfs_fget(search_string, file_name, SFS_FGET_REV);
                lcd_puts((const char*)file_name);
            } else {
                lcd_puts_P("ERROR");
            }
            break;
        default:
            // Key events in unknown state is ignored
            break;
        }
        break;
    case KEY_DOWN:
        switch (avrraven.status.state) {
        case STATE_IDLE:
            new_menu_entry = FMENU_NavigateDown(&MENU_menuHandle);
            break;
        case STATE_CONFIG_DEBUG_ENABLE:
            lcd_puts_P("DISABLE");
            avrraven.user_config.debug_enable = false;
            break;
        case STATE_CONFIG_TXTPREV_ENABLE:
            lcd_puts_P("DISABLE");
            avrraven.user_config.txtmsg_preview = false;
            break;
        case STATE_CONFIG_FW_UPGRADE:
            lcd_puts_P("USR ACK");
            avrraven.user_config.fw_rcv_auto = false;
            break;
        case STATE_CONFIG_CONNECT:
            lcd_puts_P("MANUAL");
            avrraven.user_config.join_auto = false;
            break;
        case STATE_CONFIG_IMG_RCV:
            lcd_puts_P("USR ACK");
            avrraven.user_config.fw_rcv_auto = false;
            break;
        case STATE_MAIL_COMPOSE:
        case STATE_CONFIG_NAME:
            txtedit_event(TXTEDIT_KEY_DOWN);
            break;
        case STATE_CONFIG_LCD_CONTRAST:
            lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_SPACE);
            config = lcd_config_get();
            config.contrast = numedit_buffer;
            lcd_config_set(config);
            break;
        case STATE_CONFIG_CLOCK_MIN:
            {
                timendate_clk_t set_time;
                timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // hours from current clock
                int clk = set_time.hour*100 + numedit_event(NUMEDIT_KEY_DOWN); // minutes from current editing
                lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_CONFIG_CLOCK_HOUR:
            {
                timendate_clk_t set_time;
                timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // minutes from current clock
                int clk = numedit_event(NUMEDIT_KEY_DOWN)*100 + set_time.min; // hours from current editing
                lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_CONFIG_LCD_SCROLLING:
            lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_SPACE);
            
            // Update LCD scrolling settings
            config = lcd_config_get();
            config.scrolling = (lcd_scrolling_t)numedit_value_get();
            lcd_config_set(config);
            break;
        case STATE_CONFIG_RADIO_CHANNEL:
            lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_SPACE);
            break;
        case STATE_CONFIG_RADIO_PANID:
        case STATE_MAIL_COMPOSE_ADDRESS_SET:
            lcd_num_puthex(numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_ZERO);
            break;
        case STATE_CONFIG_UNIT_TEMP:
            avrraven.user_config.unit.temp = TEMP_UNIT_FAHRENHEIT;
            lcd_symbol_clr(LCD_SYMBOL_C);
            lcd_symbol_set(LCD_SYMBOL_F);
            break;
        case STATE_CONFIG_UNIT_CLOCK:
            avrraven.user_config.unit.clock = TIME_CLOCK_UNIT_12;
            if (avrraven.user_config.unit.clock == TIME_CLOCK_UNIT_24) {
                lcd_symbol_clr(LCD_SYMBOL_AM);
                lcd_symbol_clr(LCD_SYMBOL_PM);
                lcd_num_puthex(0x2400, LCD_NUM_PADDING_ZERO);
            } else {
                lcd_symbol_set(LCD_SYMBOL_AM);
                lcd_symbol_set(LCD_SYMBOL_PM);
                lcd_num_puthex(0x1200, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_MAIL_READ:
            mbox_mail_get(&current_mail, MBOX_GET_PREV);
            if (current_mail != NULL) {
                int_temp = current_mail->size;
                lcd_puta(current_mail->data, int_temp);
                lcd_num_puthex(current_mail->address, LCD_NUM_PADDING_ZERO);
            }
            break;
        case STATE_FW_WAIT_USER_CONFIRMATION:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_AUDIO_FILE_SELECT:
            strncpy_P((char*)search_string, AUDIO_FILE_TYPE, AUDIO_FILE_TYPE_SIZE);
            if (avrraven.status.batt_low == false) {
                sfs_fget(search_string, file_name, SFS_FGET_FWD);
                lcd_puts((const char*)file_name);
            } else {
                lcd_puts_P("ERROR");
            }
            break;
        case STATE_STORAGE_FILE_LIST:
            strncpy_P((char*)search_string, "*.*", 4);
            if (avrraven.status.batt_low == false) {
                sfs_fget(search_string, file_name, SFS_FGET_FWD);
                lcd_puts((const char*)file_name);
            } else {
                lcd_puts_P("ERROR");
            }
            break;
        default:
            // Key events in unknown state is ignored
            break;
        }
        break;
    case KEY_LEFT:
        switch (avrraven.status.state) {
        case STATE_IDLE:
            new_menu_entry = FMENU_NavigateLeft(&MENU_menuHandle);
            break;
        case STATE_CONFIG_CLOCK_MIN:
            {    // Set min
                timendate_clk_t new_time;
                timndate_clock_get(&new_time, avrraven.user_config.unit.clock);
                new_time.min = numedit_buffer;
                new_time.sec = 0;
                timndate_clock_set(new_time, avrraven.user_config.unit.clock);
            }
            
            // Done numeric editing on hours
            numedit_done();
            
            // Start numeric editor on hours
            {
                timendate_clk_t current_time;
                timndate_clock_get(&current_time, avrraven.user_config.unit.clock);
                numedit_buffer = current_time.hour;
                numedit_config_t conf = {
                    .number = &numedit_buffer,
                    .min_value = 0,
                    .max_value = 23,
                    .radix = NUMEDIT_RADIX_DEC,
                    .size = 2,
                    .offset = 2
                };
                numedit_init(conf);
            }
            
            avrraven.status.state = STATE_CONFIG_CLOCK_HOUR;
            break;
        case STATE_AUDIO_FILE_SELECT:
            if (audio_playback_active() == true) {
                audio_playback_stop();
            }
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_NAME:
        case STATE_MAIL_COMPOSE:
            txtedit_event(TXTEDIT_KEY_LEFT);
            break;
        case STATE_CONFIG_RADIO_PANID:
        case STATE_MAIL_COMPOSE_ADDRESS_SET:
            lcd_num_puthex(numedit_event(NUMEDIT_KEY_LEFT), LCD_NUM_PADDING_ZERO);
            break;
        case STATE_CONFIG_UNIT_TEMP:
            break;
        case STATE_CONFIG_UNIT_CLOCK:
            break;
/*        case STATE_MAIL_READ:
            mbox_mail_getnext(&txtmsg);
            if (txtmsg != NULL) {
                int_temp = ((txtmsg->size) < LCD_SEGMENT_COUNT) ? txtmsg->size : LCD_SEGMENT_COUNT;
                mail_read_offset = ((mail_read_offset + LCD_SEGMENT_COUNT) >= txtmsg->size) ? mail_read_offset : (mail_read_offset + LCD_SEGMENT_COUNT);
                lcd_puta(&txtmsg->data[mail_read_offset], int_temp);
            }
            break;*/
        case STATE_FW_WAIT_USER_CONFIRMATION:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        default:
            // Key events in unknown state is ignored
            break;
        }
        break;
    case KEY_RIGHT:
        switch (avrraven.status.state) {
        case STATE_IDLE:
            new_menu_entry = FMENU_NavigateRight(&MENU_menuHandle);
            break;
        case STATE_CONFIG_CLOCK_HOUR:
            {    // Set hour
                timendate_clk_t new_time;
                timndate_clock_get(&new_time, avrraven.user_config.unit.clock);
                new_time.hour = numedit_buffer;
                new_time.sec = 0;
                timndate_clock_set(new_time, avrraven.user_config.unit.clock);
            }
            
            // Done numeric editing on hours
            numedit_done();
            
            // Start numeric editor on minutes
            {
                timendate_clk_t current_time;
                timndate_clock_get(&current_time, avrraven.user_config.unit.clock);
                numedit_buffer = current_time.min;
                numedit_config_t conf = {
                    .number = &numedit_buffer,
                    .min_value = 0,
                    .max_value = 59,
                    .radix = NUMEDIT_RADIX_DEC,
                    .size = 2,
                    .offset = 0
                };
                numedit_init(conf);
            }
            
            avrraven.status.state = STATE_CONFIG_CLOCK_MIN;
            break;
        case STATE_MAIL_COMPOSE:
        case STATE_CONFIG_NAME:
            txtedit_event(TXTEDIT_KEY_RIGHT);
            break;
        case STATE_CONFIG_RADIO_PANID:
        case STATE_MAIL_COMPOSE_ADDRESS_SET:
            lcd_num_puthex(numedit_event(NUMEDIT_KEY_RIGHT), LCD_NUM_PADDING_ZERO);
            break;
        case STATE_CONFIG_UNIT_TEMP:
            break;
        case STATE_CONFIG_UNIT_CLOCK:
            break;
        case STATE_FW_WAIT_USER_CONFIRMATION:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        default:
            // Key events in unknown state is ignored
            break;
        }
        break;
    case KEY_ENTER:
        switch (avrraven.status.state) {
        case STATE_DISPLAY_MESSAGE:
            // Default display avrraven.status.state
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            led_status_set(LED_OFF);
            lcd_num_clr_all();
            
            // Refresh menu function (in case it affects the display)
            menu_action = MENU_ACTION_REFRESH;
            if (current_menu_entry->action != NULL) {
                current_menu_entry->action((void*)&menu_action);
            }
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_LCD_CONTRAST:
            // Done numeric editing, write value to user configuration
            numedit_done();
            avrraven.user_config.lcd.contrast = (lcd_contrast_t)numedit_buffer;
            
            // Update LCD HW 
            config = lcd_config_get();
            config.contrast = avrraven.user_config.lcd.contrast;
            lcd_config_set(config);
            
            // Write new user configuration to EEPROM
            USER_CONFIG_STORE();
            
            // Refresh menu title
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_LCD_SCROLLING:
            // Done numeric editing, write value to user configuration
            avrraven.user_config.lcd.scrolling = (lcd_scrolling_t)numedit_value_get();
            numedit_done();
            
            // Update LCD scrolling settings
            config = lcd_config_get();
            config.scrolling = avrraven.user_config.lcd.scrolling;
            lcd_config_set(config);
            
            // Write new user configuration to EEPROM
            USER_CONFIG_STORE();
            
            // Refresh menu title
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_RADIO_CHANNEL:
            // Done numeric editing, write value to user configuration
            avrraven.user_config.channel = numedit_value_get();
            numedit_done();
            
            // Write new user configuration to EEPROM
            USER_CONFIG_STORE();
            
            // Refresh menu title
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_CLOCK_HOUR:
            {    // Set hour
                timendate_clk_t new_time;
                timndate_clock_get(&new_time, avrraven.user_config.unit.clock);
                new_time.hour = numedit_value_get();
                new_time.sec = 0;
                timndate_clock_set(new_time, avrraven.user_config.unit.clock);
            }
            
            // Done numeric editing on hours
            numedit_done();
            
            // Start show clock event
            menu_action = MENU_ACTION_REFRESH;
            if (current_menu_entry->action != NULL) {
                current_menu_entry->action((void*)&menu_action);
            }
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_CLOCK_MIN:
            {    // Set min
                timendate_clk_t new_time;
                timndate_clock_get(&new_time, avrraven.user_config.unit.clock);
                new_time.min = numedit_value_get();
                new_time.sec = 0;
                timndate_clock_set(new_time, avrraven.user_config.unit.clock);
            }
            
            // Done numeric editing on minutes
            numedit_done();
            
            // Start show clock event
            menu_action = MENU_ACTION_REFRESH;
            if (current_menu_entry->action != NULL) {
                current_menu_entry->action((void*)&menu_action);
            }
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_DEBUG_ENABLE:
            // Write new user configuration to EEPROM
            USER_CONFIG_STORE();
            
            // Refresh menu title
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_RADIO_PANID:
            // Done numeric editing on hours
            numedit_done();
            
            // Write new user configuration to EEPROM
            USER_CONFIG_STORE();
            
            // Refresh menu title
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_UNIT_TEMP:
        case STATE_CONFIG_UNIT_CLOCK:
        case STATE_CONFIG_TXTPREV_ENABLE:
        case STATE_CONFIG_FW_UPGRADE:
        case STATE_CONFIG_CONNECT:
        case STATE_CONFIG_IMG_RCV:
            // Write new user configuration to EEPROM
            USER_CONFIG_STORE();
            
            // Refresh menu title
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_MAIL_PREVIEW:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            menu_action = MENU_ACTION_REFRESH;
            if (current_menu_entry->action != NULL) {
                current_menu_entry->action((void*)&menu_action);
            }
            led_status_set(LED_OFF);
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_AUDIO_FILE_SELECT:
            if (audio_playback_active() == false) {
                audio_playback_start(file_name, false);
            } else {
                audio_playback_stop();
            }
            break;
        case STATE_STORAGE_FILE_LIST:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_FW_WAIT_USER_CONFIRMATION:
            avrraven.status.state = STATE_FW_WRITE_INIT;
            break;
        case STATE_IDLE:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            if (current_menu_entry->action != NULL) {
                current_menu_entry->action((void*)&menu_action);
            }
            break;
        case STATE_AUDIO_RECORD:
            audio_record_stop();
            lcd_symbol_clr(LCD_SYMBOL_MIC);
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_CONFIG_NAME:
            txtedit_event(TXTEDIT_KEY_ENTER);
            txtedit_done();
            USER_CONFIG_STORE();
            // Print the menu title to the display
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_MAIL_READ:
            lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry));
            // If any unread mail, show closed envelope
            if (mbox_unread() == true) {
                lcd_symbol_set(LCD_SYMBOL_ENV_MAIN);
                lcd_symbol_set(LCD_SYMBOL_ENV_CL);
                lcd_symbol_clr(LCD_SYMBOL_ENV_OP);
            // If all mail read, show open envelope
            } else {
                lcd_symbol_set(LCD_SYMBOL_ENV_MAIN);
                lcd_symbol_set(LCD_SYMBOL_ENV_CL);
                lcd_symbol_set(LCD_SYMBOL_ENV_OP);
            }
            // show number of mails on display
            int_temp = mbox_mail_count_get();
            lcd_num_putdec(int_temp, LCD_NUM_PADDING_SPACE);
            mbox_close();
            avrraven.status.state = STATE_IDLE;
            break;
        case STATE_MAIL_COMPOSE:
            txtedit_event(TXTEDIT_KEY_ENTER);
            txtedit_done();
            mbox_mail_buffer_put(new_mail_buffer);
            {
                lcd_puts_P("ADDRESS");
                    numedit_config_t conf = {
                        .number = &numedit_buffer,
                        .min_value = 0,
                        .max_value = UINT16_MAX,
                        .radix = NUMEDIT_RADIX_DEC,
                        .size = 1,
                        .offset = 0
                    };
                numedit_init(conf);
            }
            numedit_buffer = 0x0000; // default address
            lcd_num_puthex(numedit_buffer, LCD_NUM_PADDING_ZERO);
            avrraven.status.state = STATE_MAIL_COMPOSE_ADDRESS_SET;
            break;
        case STATE_MAIL_COMPOSE_ADDRESS_SET:
            avrraven.status.trans_seq_nmbr = mbox_mail_send(numedit_value_get(), txtedit_size_get());
            avrraven.status.state = STATE_MAIL_SEND_INIT;
            numedit_done();
            mbox_close();
            break;
        default:
            lcd_puts_P("CANCELED");
            led_status_set(LED_FAST_BLINK);
            lcd_num_clr_all();
            avrraven.status.state = STATE_DISPLAY_MESSAGE;
            break;
        }
        break;
    case KEY_NO_KEY:
        // Do nothing?
        break;
    default:
            // Key events in unknown state is ignored
        break;
    }
    
    // Navigate menu if new menu entry is different from last
    if (new_menu_entry != current_menu_entry) {
        navigate_menu(current_menu_entry, new_menu_entry, menu_action);
    }
    
    // After processing the key event it is safe to enable auto key
    auto_key_state = key_state;
    if (key_state != KEY_NO_KEY) {
        if (auto_key_registered == false) {
            long delay;
            if (auto_key_wait == true) {
                delay = 300;
                auto_key_wait = false;
            } else {
                asy_tmr_put(auto_key_timer);
                delay = 80;
                auto_key_registered = true;
            }
            auto_key_timer = asy_tmr_get(int_evt_key, (void*)&auto_key_state, delay);
        }
    } else {
        asy_tmr_put(auto_key_timer);
        auto_key_wait = true;
        auto_key_registered = false;
    }
}

void int_evt_check_key(void* evt)
{
    static bool first_time = true;          // Static variable used as flag to indicate first execution of function
    static key_state_t last_key_state;      // Variable hodling last value of the joystick. Used to detect changes in joystick state
    
    /* Check joystick state. Post event if any change since last
     * First time function is executed no event is posted. This is
     * done to not respond if joystick activated while booting
     */
    key_state_t new_key_state;
    if (first_time) {
        last_key_state = key_state_get();
        new_key_state = last_key_state;
        first_time = false;
    } else if((new_key_state = key_state_get()) != last_key_state){
        last_key_state = new_key_state;
        vrt_post_event(int_evt_key, (void*)&last_key_state);
    }
}

void int_evt_lcd_shift_left(void* evt)
{
    lcd_text_shift_left();
}

void int_evt_lcd_cursor_toggle(void* evt)
{
    lcd_cursor_toggle();
}

void int_evt_lcd_num_refresh(void* evt)
{
    lcd_num_refresh();
}

void int_evt_update_batt(void* evt)
{
    int16_t vcc_batt = battery_voltage_read();
    
    lcd_symbol_battery_empty();
    if (vcc_batt>2000) {
        lcd_symbol_set(LCD_SYMBOL_BAT_CAP1);
    }
    if (vcc_batt>2500) {
        lcd_symbol_set(LCD_SYMBOL_BAT_CAP2);
    }
    if (vcc_batt>2800) {
        lcd_symbol_set(LCD_SYMBOL_BAT_CAP3);
    }
    
    // Indicate low battery if voltage less than 2.6 V
    if (avrraven.status.batt_low == false) {
        if (vcc_batt<2600) {
            avrraven.status.batt_low = true;
            lcd_symbol_set(LCD_SYMBOL_ATT);
            mbox_deinit();
            sfs_deinit();
        }
    }
}

void int_evt_show_clock(void* evt)
{
    static bool col = false;
    timendate_clk_t clk;
    timndate_clock_get(&clk, avrraven.user_config.unit.clock);
    int16_t display_clock = clk.hour*100 + clk.min;
    lcd_num_putdec(display_clock, LCD_NUM_PADDING_ZERO);
    if ((col = !col) == true){
        lcd_symbol_set(LCD_SYMBOL_COL);
    } else {
        lcd_symbol_clr(LCD_SYMBOL_COL);
    }
}

void int_evt_toggle_num_digit(void* evt)
{
    int8_t digit_mask = *(int8_t*)evt;
    lcd_num_enable(digit_mask);
}

void int_evt_audio(void* evt)
{
    audio_event_handler();
}