User Interface (Part 3)

Part 1234, 5

Now that we have decided how the menus will display on the LCD, let’s investigate the firmware. Writing some code for driving menus is not so hard. But making this code flexible enough for driving “any” menu structure makes your programmer’s life quite dense!

The basis for my code is a vector which contains the definition of the menus. Fist of all, let’s investigate one single entry for which I created a struct variable

struct mnuItem{ 
	int16_t min; // min value of MNU_TYP_PARAM or 0 
	int16_t max; // max value of MNU_TYP_PARAM or number (-1) of sub menu items for all other menu items
	uint8_t nextMenuIndex; // Nex menu item
	uint8_t menuType; // One of MNU_TYP_x
	uint8_t lastIndex; // Must be set to 0 as default
	char *caption;  // Menu caption
};

The min parameter is the lower bound for a parameter value, or the starting sub index value (In fact 0, always),
Same principle for max parameter. When dealing with a manu item, max tells how many sub menus exist below this one.
nextMenuIndex tells where to jump to when the mnuItem is a root menu item
menuType can be of type: MNU_TYP_ITEM, MNU_TYP_PARAM, MNU_TYP_RETURN, MNU_TYP_EXIT
lastIndex records the root menuIndex in order to scroll up and down in the menu structure
caption is a pointer to the menu caption string.

All menu items are recorded in a vector of mnuItem variables. Here is an example for a simple alarm clock application

struct mnuItem vMnuItems[] = { 
//min,max, sub,              last,          type
	{ X,	X,   X,	           X,   0,  MSG_FIRMWARE},  
	{ 0,	3,	 2, MNU_TYP_ITEM,   0,    CAP_SELECT},  
	// Main menu
	{ 0,	3,   6, MNU_TYP_ITEM,   0,      CAP_TIME},  
	{ 0,	3,  10, MNU_TYP_ITEM,   0,      CAP_DATE},    
	{ 0,	3,  14, MNU_TYP_ITEM,   0,     CAP_ALARM},  
	{ X,  X,   0, MNU_TYP_EXIT,   0,      CAP_EXIT},	   
	// Time
	{ 0, 23,   0, MNU_TYP_PARAM,  0,     CAP_HOURS},   
	{ 0, 59,   0, MNU_TYP_PARAM,  0,   CAP_MINUTES}, 
	{ 0, 59,   0, MNU_TYP_PARAM,  0,   CAP_SECONDS}, 
	{ X,  X,   1, MNU_TYP_RETURN, 0,    CAP_RETURN}, 
	// Date
	{ 0, 31,   0, MNU_TYP_PARAM,  0,       CAP_DAY},  
	{ 0, 12,   0, MNU_TYP_PARAM,  0,     CAP_MONTH},   
	{ 0, 99,   0, MNU_TYP_PARAM,  0,      CAP_YEAR},    
	{ X,  X,   1, MNU_TYP_RETURN, 0,    CAP_RETURN},  
	// Alarm
	{ 0, 23,   4, MNU_TYP_PARAM,  0,     CAP_HOURS},  
	{ 0, 59,   4, MNU_TYP_PARAM,  0,   CAP_MINUTES}, 
	{ 0,  1,   4, MNU_TYP_PARAM,  0,    CAP_ACTIVE}, 
	{ X,  X,   1, MNU_TYP_RETURN, 0,    CAP_RETURN} 
};

You must pay a lot of attention when transfering your menu structure to this vector or you may get lost during navigation.
Notes:

  • X is a global variable which means “any value” to me.
  • It would possible to trick min and max values in order to get rid of MNU_TYP_xxx variable and save 8 bits for each mnuItem. But you loose the readability of the menu structure…

Next Post on same subject

Leave a Reply

You must be logged in to post a comment.