TinyMenu

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just wondering if anyone has been successful in getting this project to work? I've added some code to make the buttons function and maped the lcd functions to the driver I'm using, but nothing apears on the screen and after a bit of fiddling around it seems that nothing is even trying to be drawn to the screen.

I can't find any other code to do menus and I'm not goot enough in c to make my own (in 20,000 lines or less...) so I'm sort of stuck!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The AVR Butterfly source code contains a state machine based menuing system for the Butterfly's joystick and LCD.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry haven't been around too much to check on posts here (my workbench isn't set up yet from a move a few months ago & haven't been working on projects too much).

don't know if you're still trying to get things to work -- i did munge the example code a bit (i tend to write code to test packages that i include, but sometimes it gets a little out of date and buggy, as i move to using the core code on other projects). i've used the core code though with both Nokia and 44780-based displays.

i'll update the project with working example code when i have my bench back up and i can test things decently.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, that would be great!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

try this:

#include 
#include 
#include 

#include "spin_delay.h"
#include "lcd_pcd8544.h"
#include "lcd_pcd8544_text.h"
#include "tinymenu.h"
#include "joystick.h"

void my_select(void *arg, char *name);

menu_t sub1_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.entry =  {
		{.flags = 0,
		 .select = my_select,
		 .name = "s2",
		 .value = 0,
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "s3",
		 .value = 0,
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "s4",
		 .value = 0,
		},
	},
	.num_entries = 3,
	.previous = NULL,
};

menu_t sub2_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.entry = {
		{.flags = 0,
		 .select = my_select,
		 .name = "s5",
		 .value = 0,
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "s6",
		 .value = 0,
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "s7",
		 .value = 0,
		}
	},
	.num_entries = 3,
	.previous = NULL,
};

menu_t main_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.entry = {
		{.flags = MENU_FLAG_SUBMENU,
		 .select = NULL,
		 .name = "submenu 1",
		 .value = &sub1_menu,
		},
		{.flags = MENU_FLAG_SUBMENU,
		 .select = NULL,
		 .name = "submenu 2",
		 .value = &sub2_menu,
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "something",
		 .value = 0,
		}
	},
	.num_entries = 3,
	.previous = NULL,
};

menu_context_t menu_context = {
	.x_loc = 0,
	.y_loc = 0,
	.height = 2,
	.width = 10,
	.menu = NULL,
};

void my_select(void *arg, char *name)
{
	lcd_clear();
	lcd_puts("Selected: ");
	lcd_puts(name);
	
	ms_spin(750);

}

int main()
{
	uint8_t j;

	
	joystick_init();
	
	menu_enter(&menu_context, &main_menu);
	
	while (1) {
		ms_spin(50);
		j = joystick_read();
	
		switch(j) {
			case JOYSTICK_UP:
				menu_next_entry(&menu_context);
				break;
			case JOYSTICK_DOWN:
				menu_prev_entry(&menu_context);
				break;
			case JOYSTICK_LEFT:
				menu_exit(&menu_context);
				break;
			case JOYSTICK_RIGHT:
			case JOYSTICK_BUTTON:
				menu_select(&menu_context);
				break;
		}
	}
}

not able to fully test right now, but should work -- i wasn't entering the main menu, and the submenus weren't connected... (oops). i changed the way i was doing some things and the example code was somewhere between the old and new ways.

i haven't played with the butterfly code, but i've heard it's pretty hard to deal with the state machine mechanics; i threw this stuff together mainly for a light machine i was working on, where i'd need to make it really easy to change hz values, etc... i've got some widgets i might add to this code too, for inputting times (h:m:s) and hz values and the like, although they're a little messier, and not sure how useful they'd be to most folks...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your updated example Tymm. I'm also keen to get this working but have noticed something else still slightly wrong with your menu_t declarations in your latest example. They don't appear to match the typedefs in the header. For example, the menu_t structure in the header file has the following member order:
top_entry, current_entry, num_entries, *previous, entry[]

however, your example has this order:
top_entry, current_entry, entry[], num_entries, *previous

Any further assistance would be much appreciated as I'm sure once this is sorted, the menu system will be invaluable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hmm; are you getting a compiler error?

at least in the gcc version i'm using the order of assignments really isn't important, esp. since they indicate the name of the data element that's being assigned so the compiler can figure things out (can check version if you want; AFAIK all recent gcc versions support order independent assignments of structure elements). i think this style of assignment is a gcc-ism though; if you're using another compiler it's very likely you'd have to actually assign things one data element at a time... and in such a case you'd probably want to change the
menu_t definition for entries to be a menu_entry_t *...

i usually make a point to write stuff much more portably, but with these kinds of assignments, the gcc-isms make it so much easier... and i'm on a hobbyist (gnu tools) budget :)

                               

menu_entry_t main_menu_entries[3];
menu_t main_menu;
   
...
main() {
...
    main_menu.top_entry = 0;
    main_menu..current_entry = 0;
    main_menu.entry = main_menu_entries;
    main_menu.num_entries = 3,
    main_menu.previous = NULL,

    main_menu_entries[0].flags = MENU_FLAG_SUBMENU;
    main_menu_entries[0].select = NULL;
    main_menu_entries[0].name = "submenu 1";
    main_menu_entries[0].value = &sub1_menu;

    main_menu_entries[1].flags = MENU_FLAG_SUBMENU;
    main_menu_entries[1].select = NULL;
    main_menu_entries[1].name = "submenu 2";
    main_menu_entries[1].value = &sub2_menu;

    main_menu_entries[2].flags = 0;
    main_menu_entries[2].select = my_select;
    main_menu_entries[2] .name = "something";
    main_menu_entries[2].value = 0;
...

   
 
};

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I must admit I didn't try the code without modifying the elements' order as I assumed it would cause a failure. I'm using avr-gcc 3.4.3 (WinAVR). Although I have used the element sequence that matches your tinymenu.h structure definition, everything compiles error-free.

However, the problem I have is that my LCD is 2 lines by 24 characters and the selected item gets out of step with the keypresses. For example, the main menu items are: "Display", "Zone Modes" and "Set System". The display begins by displaying "*Display" on the first line and "Zone Modes" on the second, as expected. Pressing the DOWN key moves the asterisk to the second line. The second press of DOWN doesn't change the first two items displayed, it only removes the asterisks. The third press of DOWN changes the display (scrolls the items vertically) but again with no asterisks. Pressing the UP key twice places an asterisk against "*Set System", as if a pointer is getting lost. I have replaced your joystick control by a fully-debugged and debounced 4-key system: MENU/UP/DOWN/SELECT.

My menu structure for testing is:

menu_t sub1_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.num_entries = 2,
	.previous = NULL,
	.entry =  {
		{.flags = 0,
		 .select = my_select_sub1,
		 .name = "Date & Time",
		 .value = 0
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "Temperatures",
		 .value = 0
		},
	}
};

menu_t sub2_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.num_entries = 3,
	.previous = NULL,
	.entry = {
		{.flags = 0,
		 .select = my_select,
		 .name = "s5",
		 .value = 0
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "s6",
		 .value = 0
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "s7",
		 .value = 0
		}
	}
};

menu_t sub3_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.num_entries = 4,
	.previous = &sub2_menu,
	.entry = {
		{.flags = 0,
		 .select = my_select,
		 .name = "Set Time",
		 .value = 0
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "Set Hysteresis",
		 .value = 0
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "Reset Cumulatives",
		 .value = 0
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "Reset Errors",
		 .value = 0
		}
	}
};

menu_t main_menu = {
	.top_entry = 0,
	.current_entry = 0,
	.num_entries = 4,
	.previous = NULL,
	.entry = {
		{.flags = MENU_FLAG_SUBMENU,
		 .select = my_select_sub1,
		 .name = "Display",
		 .value = &sub1_menu,
		},
		{.flags = MENU_FLAG_SUBMENU,
		 .select = NULL,
		 .name = "Zone Modes",
		 .value = &sub2_menu,
		},
		{.flags = MENU_FLAG_SUBMENU,
		 .select = NULL,
		 .name = "Set System",
		 .value = &sub3_menu,
		},
		{.flags = 0,
		 .select = my_select,
		 .name = "something",
		 .value = 0
		}
	}
};

menu_context_t menu_context = {
	.x_loc = 0,
	.y_loc = 0,
	.height = 2,
	.width = 18,
	.menu=NULL,
};

I have defined CONFIG_TINYMENU_USE_CLEAR and defined menu_set_pos(x,y) as lcd_gotoxy(x,y) where my goto function starts at x=0, y=0. I noticed you multiplied both x and y by 6 in your tinymenu_hw.h definition. Is this significant? Any assistance is appreciated :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My understanding of the *6 thing was because of a graphic display where 1 character is 6 pixels wide. Could be wrong!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm sure you're right. It's probably something related to graphics spacing. My guess is that the selection problem I am experiencing lies somewhere in menu_print_entry(). Ideally, it would be nice to have a detailed document explaining the menu usage and all the options... My knowledge of C is reasonable but not quite expert enough to fully comprehend the inner-workings of this!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yep, the 6 is for width of graphic characters -- it's currently configured for use with my nokia display routines. for a character display you shouldn't need the multiplication.

it's funny; i actually hadn't expected that many people to download and use my packages; mainly put 'em up since i put together things i thought were kinda clever and could be useful, more as a basis on which to build, and figured people would write me directly if they were having difficulties... but it looks like i should take the time to focus on making them more usable, outside the base code.

so basically beyond the example (which i can definitely pretty up), the set_pos in the _hw.h is confusing... anything else that would make it more usable?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I expect many others are also appreciating the compactness of your code and the usefulness of this project in a tight code environment. Working 'out of the box' was never my expectation - obviously there would be some tweaks and adjustments needed!

On the surface, the code looks as if it should work once a couple of items have been configured. Unfortunately, that was not my experience. The greatest help would be a little more documentation (for those of us still getting to grips with C). For example, an explanation outlining the allowable values and correct use of the elements: flags, select, name and value within the menu_t structure would be most welcome. Most important would be a generic example which has been thoroughly tested.

TINYMENU_CONFIG_COMPACT is referenced in tinymenu.h, but seems to have become CONFIG_TINYMENU_COMPACT in tinymenu.c. Not a major problem, but may lead to confusion.

Do you have any suggestions as to why the selected item might get out of step with the display (and the '*' disappear)? It's leaving me baffled!

I hope you don't think I'm asking too much...
Best wishes,

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not at all -- i asked for what would help :)

ok, so i found there are bugs in the code that are causing what you're talking about.

the line in menu_display():

menu_print_entry(disp_entry, context->width, (menu->current_entry == dindex - 1));

should be

    menu_print_entry(disp_entry, context->width,
               (menu->current_entry + 1 == dindex + menu->top_entry));

and in menu_next_entry()

    menu->top_entry = menu->current_entry - context->height;

should be

    menu->top_entry = menu->current_entry - context->height + 1;

(sigh. that's pretty embarrassing last testing was done on a display with enough lines that scrolling wasn't necessary... so apparently i got lax on that bit :( )

lemme know if things work with these changes...

thanks,

-Tymm

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

btw, i put a new package at http://www.booyaka.com/~tymm/avr... -- I haven't put together a good README yet, and the example app is the one above (which could be better documented & laid out), but should be at least fixed :) i'll update the version in the academy after it's been tested (and hopefully i'll get time to do the README too)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Tymm, I took the step of understanding exactly what the code is meant to do. In menu_display(), I reached a similar conclusion to you, which also works:

	menu_print_entry (disp_entry, context->width,
    ((menu->current_entry - menu->top_entry)==dindex-1) );

I had just sorted that part before seeing your reply. Your other change, to menu_next_entry(), now gives the desired effect.

Thank you for your assistance - everything is displaying perfectly now :D

Next, I will investigate assigning functions to the menu items...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BTW, I uploaded a new package w/the fixed test code, scrolling bugs fixed, minor formatting things, and a small README added. Curious about feedback to see if this all helps make the package easier to use.

Thanks,

-Tymm

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!
I implemented tinymenu in my project and I need multilanguage menu (English,Deutsch,Polish).
Any ideas ?
I need help.
Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you can either set them up as seperate menus (just with all the functions etc copied) or hack the code to print the menu entry in the given language; should just take a few lines of added code to have the entry names in an array rather than a single string...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello!
First: excuse me for my wrong English!
Why steps my menu more than one? Example: submenus name are sub1,sub2,sub3,sub4. When I step it, selected only sub1 and sub4. Sub2 and sub3 never selected. How can I fix it?
Thank you very much!
Jozsef Kovacs
Hungary

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It was Developer Error. :)
I could not clear a variable and function called again and again. :)