View Full Version : Flexible menu system for spin?

05-31-2010, 05:50 AM
Very recently i have found out that the current menu system that i am using will not work do to a ton of recursive method calls. I asked about different types of alternative menu systems and i got back varied results. I was just wondering if anybody knows anything about a better menu system in a GOTO-Less spin structure. I thank the people who have already helped me and i am·glad to find such a friendly forum.

05-31-2010, 09:20 AM
A menu system is generally optimized for a hardware UI -- what kind of display and input are you using?

Jon McPhalen
Hollywood, CA

05-31-2010, 10:04 AM
I am using a character 20x2 lcd with a serial protocol and a parallax ps/2 keyboard. All i need is something simple.

05-31-2010, 10:32 AM
How about using a separate object for each menu,·along with·cognew and cogstop (to kill off the old menus)?

You make·menu selections going down and it starts new objects along the way and kills off the menus it is leaving behind.

Then opposite going back up.

Would this use·up stack space? (I don't know???)

05-31-2010, 10:49 AM
Hey, bill190. That sounds like an idea. I just might try that out. UGGHH, it is has been so difficult trying to figure out what to do.

T Chap
05-31-2010, 12:00 PM
I am not sure if this offers any help to your problem, but here is what I do for a menu system on a 2x16 LCD with several buttons to navigate. The buttons are < > for navigating through each item in the menu. Then -NO and +YES buttons to increment/dec the values of that menus parameter(s). Then ENTER for various menu functions. Last, the SETUP button which enters the menu list from the main loop running elsewhere. I use a PCF8574 I2C device to read the 6 button states.

There are two main parts of the menu, the MAINMENU and the List of Case Statements. Then, create the methods as needed, each method requires the section to trap the buttons as they are pressed. Then there are the individual methods for changing the values as needed. Maybe you can at least get some ideas from this system.

PUB MainMenu | n
n := UpdateIndex 'updateindex is stored in eeprom so each time entering menu, you are at the same item as last visited.
CLS 'clear LCD
ser.str(3, string("Main Menu"))
ser.str(3, string("< > View Options"))
repeat while ina[setupkey] == 1 'trap here till button released to start menu
If setupkeys == leftbut
n := n - 1 #> 1
spk.beep(19, 3500, 100)
UpdateIndex := n
WriteUpdateIndex 'update the menu position in eeprom for future use.
elseIf setupkeys == rightbut
n := n + 1 <# 28 '<<<<<<always update this value based on number of menu items
spk.beep(19, 3500, 100)
UpdateIndex := n
trap := on
If setupkeys == setupbut
spk.beep(19, 3500, 100)
setupled := on 'led = of
CLS 'clear screen
return 1

PUB Option(N) 'examples
Case N
1: if Method1 == stop
2: if Method2 == stop
3: if Method3 == stop

PUB IDSet 'example set the ID for this device
go(0, 0)
ser.str(3, string("Set ID"))
go(1, 0)
ser.decf(3, ID, 6)
ReadSetupKeys 'reads I2C device to check button states
if setupkeys == yesbut
ID := ID + 1 <# 127
go(1, 0)
ser.decf(3, ID, 6)
spk.beep(19, 2500, 200)
if setupkeys == nobut
ID := ID - 1 #> 0 ' limit min
go(1, 0)
ser.decf(3, ID, 6)
spk.beep(19, 2500, 200)
if setupkeys == enterbut
WriteID 'write the value to eeprom

repeat while (setupkeys == yesbut) or (setupkeys == nobut)
ReadSetupKeys 'reads I2C device to check button states
if trap
if setupkeys == leftbut or setupkeys == rightbut ' test
repeat scrolldelay ' delay x if is still held from initial entry press test
ReadSetupKeys 'reads I2C device to check button states
if (setupkeys == leftbut) or (setupkeys == rightbut) or (setupkeys == setupbut) 'get out of here if < or >
return stop
trap~ 'remove initial trap state

Post Edited (Todd Chapman) : 5/31/2010 5:05:27 AM GMT

05-31-2010, 12:55 PM
Ravenkallen: At this point in your studies I might make a humble suggestion.

Get yourself set up with a BASIC that supports functions and procedures on your PC. Try to create what you want in a menu system using that. Make the rule that you will not use GOTOs in your code.

You can simulate your LCD with a couple of lines of screen output and use stub functions for the actions that the menu selections will ultimately trigger.

It will be much easier to write, test, debug your menu system on the PC and in a language you are somewhat familiar with.

When you have that working you will see how you can write the same thing in Spin.

For me, the past is not over yet.

05-31-2010, 01:33 PM
Here's a thread about a LCD menu:


Here's another one, 3rd post contains a MenuDemo.spin. It's meant for a TV driver, but it should be easy to change it and at least gives you an idea how it can be done:

Post Edited (MagIO2) : 5/31/2010 6:44:06 AM GMT

06-01-2010, 04:21 AM
Thanks guys. I was kind of asking about menu systems in theory. Like an explanation on how to go about making one of them, like a tutorial of sorts. I googled various menu types and i didn't find any important info.

06-01-2010, 01:36 PM
Well .. what's the theory behind a menu system?

It's like any tree .. you have a root (the main menu) and then the root has nodes ( menu entries ) which can be a branch ( submenu-entry ) or a leaf ( let's call it the action entry because it really starts some code ).

So, first of all you have to think about a data-structure which allows to define this tree-structure.
Just as an example, you could have a structure that describes the (sub)menu: pointer to (sub)menu-name, number of entries (NOE)
followed by·a structure that describes a menu entry: type ( branch or leaf ), pointer to name, pointer to submenu ( in case of a leaf it's used·to·store a function number )

Next thing is a piece of code which can handle this data-structure according to the given user input.
With up/down the previous/next menu entry is getting the focus within the range of 1 to number of entries (NOE)·of the actual menu description.
With enter the focused entry is selected. If it's a leaf the function number of the menu entry is passed to the code that executes the functions. ( return value or global variable ).
If the selected entry is a branch, the code switches to the submenu.
With ESC the menu-system returns to the parent menu.

[·By the way ... recently there was a thread about recursive function calls ... here a recursive function call can help to keep the menu-handler easy.
You start with menuHandler( @rootmenu ) and each submenu is doing a recursive call menuHandler( pointer to submenu ). Hitting ESC is then as easy as RETURN - you should only prevent that the first menuHandler should not allow an ESC ]

The third thing needed is a presentation layer. This is needed to print the menu on the device you have. It's a good idea to keep the menu-handler separated from the code that prints the menu. Because then it's easy to use the same data-structure and menu-handler for different systems (text LCD, TV, graphical LCD).
You can do that by defining an interface to the presentation part, for example just one function that's used by the menu-handler like
printMenu( pointer to actual menu, number of entry having the focus)

Then you need the code that uses the menu-system. There you have 2 possibilities:
1. the using code simply starts the menu-system (in it's own COG)·which then runs independend. Selected menu entries (function number of the leaf) will be communicated via a communication buffer.
2. the menu is the main-program and calls a function handler. The function handler is a case statement which contains the right function call per function number

The difference? 1 needs an additional COG but it will always react on user-input. Maybe code to sync with the functionHandler is needed, as some functions might want to finish the job before the next selection can be done.
2 is running the menu in the initial SPIN-COG. If a function want's to run in parallel the functionHandler can also do a COGNEW.

So from a functional point of view there is no real difference except that in 1 the menu output device is always blocked by the menu-system, in 2 the function can delete the menu and do it's own output.

Hope that helped ;o)

PS: Practice is better than talking, so start writing your own menu-system and you'll very soon face the first problems (or not) and we can go on with discussing ;o)