|
|
View previous topic :: View next topic |
Author |
Message |
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 1:00 am |
|
|
Greetings All,
I have been digging around the forums all day and still can't come up with an answer to my obviously not-so-unique problem!
Basically, I am trying to implement a menu system on an LCD - four button input, enter/escape/up/down. This is a hierarchical structure and nested menus are allowed such that from one parent menu, there may be multiple child menus each leading to other child menus and eventually to separate menu items which will effect an action upon selection.
At this stage, I have built something with switch/case statements - but the code is getting really ugly.. I'm up to some several hundred lines and it is getting rather unmanageable and certainly not flexible if I need to add/delete entries etc.
As mentioned above, I have been digging in the forums and have seen a number of approaches ranging from case based solutions like mine to some elegant solutions - however puntuated with arguments about compiler support for pointers to constants and/or functions.
I am using the latest version of the compiler - and I would *greatly* appreciate some guidance as to how I should be going about this task in terms of manageability, flexibility, ease of coding and elegance - bearing in mind compiler support for the solution recommended (!).
Thank you in advance and looking forward to hearing from someone soon..
//ak. |
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
Re: Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 1:23 am |
|
|
kanemoto wrote: | Basically, I am trying to implement a menu system on an LCD - four button input, enter/escape/up/down. This is a hierarchical structure and nested menus are allowed such that from one parent menu, there may be multiple child menus each leading to other child menus and eventually to separate menu items which will effect an action upon selection. |
Sounds like a tree. You could implement your menu as a tree, where every node has a pointer to it's parent. It will not be very RAM-efficient, but I think, it will be manageable and reusable.
Code: |
#define MAX_CHILDREN 5 // let's say that there will be no more then 5 menu items at a time
sMenuNode* g_pMenuRoot;
// one node of the tree
struct sMenuNode
{
pParent* sMenuNode; // pointer to the parent node
pChild* sMenuNode[MAX_CHILDREN]; // pointers to the child nodes
int iStringID; // a link to the menu item text in the ROM. CCS compiler doesn't support pointers to ROM.
};
sMenuNode* g_pMenuRoot; // root of the menu tree
|
Well, it's a long shot...
. |
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
Re: Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 2:29 am |
|
|
kender wrote: | kanemoto wrote: | Basically, I am trying to implement a menu system on an LCD - four button input, enter/escape/up/down. This is a hierarchical structure and nested menus are allowed such that from one parent menu, there may be multiple child menus each leading to other child menus and eventually to separate menu items which will effect an action upon selection. |
Sounds like a tree. You could implement your menu as a tree, where every node has a pointer to it's parent. It will not be very RAM-efficient, but I think, it will be manageable and reusable.
Code: |
#define MAX_CHILDREN 5 // let's say that there will be no more then 5 menu items at a time
sMenuNode* g_pMenuRoot;
// one node of the tree
struct sMenuNode
{
pParent* sMenuNode; // pointer to the parent node
pChild* sMenuNode[MAX_CHILDREN]; // pointers to the child nodes
int iStringID; // a link to the menu item text in the ROM. CCS compiler doesn't support pointers to ROM.
};
sMenuNode* g_pMenuRoot; // root of the menu tree
|
Well, it's a long shot...
. |
Thanks for that - however how do I handle potentially different functions called per menu item and also arguments (if needed) - such that one menu item - if selected - calls "function1(param1)" and another menu item calls "function2(param2)"?
Also - is there a neater way to handle the menu text instead of having to manually track the stringID to the menunode?
Thanks again!
//ak. |
|
|
kender
Joined: 09 Aug 2004 Posts: 768 Location: Silicon Valley
|
Re: Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 2:40 am |
|
|
kanemoto wrote: | Thanks for that - however how do I handle potentially different functions called per menu item and also arguments (if needed) - such that one menu item - if selected - calls "function1(param1)" and another menu item calls "function2(param2)"? |
Well, in the PC world it would be possible to add to the tree node a pointer to the function, which handles it. However, PIC doesn't support pointers to the functions like PC does. I think, there is a workaround (which I've never tried, therefore I'm a bad adviser) - look for it in the archives. |
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
Re: Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 3:26 am |
|
|
Quote: |
Well, in the PC world it would be possible to add to the tree node a pointer to the function, which handles it. However, PIC doesn't support pointers to the functions like PC does. I think, there is a workaround (which I've never tried, therefore I'm a bad adviser) - look for it in the archives. |
Actually with the workaround however, it stops being an elegant solution though. ;)
However having said that - looking at the CHANGES list:
3.160 Pointers to functions are now supported
So does this mean all is well?
If so - can you please help me with a simple example in elegance please?
//ak. |
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
Re: Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 4:03 am |
|
|
Quote: |
Well, in the PC world it would be possible to add to the tree node a pointer to the function, which handles it. However, PIC doesn't support pointers to the functions like PC does. I think, there is a workaround (which I've never tried, therefore I'm a bad adviser) - look for it in the archives. |
Oh, and the other thing is that execution speed is not critical, so in terms of RAM efficiency, will your suggestion will for 200 odd distinct menu nodes on a 16f876a or 18f252 (my two options at the moment)? I think that defining each of the nodes separately will eat up all the RAM right?
//ak. |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1635 Location: Perth, Australia
|
Re: Menus: linked lists, case/switch, function pointers? |
Posted: Mon Oct 17, 2005 6:49 am |
|
|
[quote="kanemoto"] Quote: |
will your suggestion will for 200 odd distinct menu nodes on a 16f876a or 18f252 (my two options at the moment)? I think that defining each of the nodes separately will eat up all the RAM right?
//ak. |
Tough choice. A superceded processor (the PIC18F252) or an inferior processor (16F876a). I would go for a PIC18F2520 or similar which give you a lot more program memory as well as other system resources for around the same price point. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
|
Posted: Mon Oct 17, 2005 2:11 pm |
|
|
I did indeed - and was wondering whether this was still valid or not - as it appears to be trying to overcome the limitation regarding pointers to functions - which - according to the version/changes log - is now supported as of 3.160 directly without having to go use your workaround?
However there is another post you made further down:
Code: |
/* local typedefs */
typedef rom struct _cmd_t
{
const rom char *pStr; /* command */
void (*pFunction) (enum porttypes port, char *pCmd, char *pArgs); /* command function */
const rom char *pDescription; /* command description (for help) */
} COMMAND_DATA;
static COMMAND_DATA CommandData[] =
{
/* hidden commands - description is NULL */
{ { "help" }, VHelpCommand, { NULL } },
{ { "OK" }, NULL, { NULL } },
{ { "RING" }, AnswerCommand, { NULL } },
{ { "CONNECT" }, ConnectCommand, { NULL } },
{ { "TEST" }, SelfTestCommand, { NULL } },
{ { "VIRGINIZE" }, VirginCommand, { NULL } },
{ { "checksum" }, ChecksumCommand, { NULL } },
{ { "bootmode" }, BootCommand, { NULL } },
#ifdef DEBUG_DST
{ { "timeset" }, TimeSetCommand, { NULL } },
{ { "dateset" }, DateSetCommand, { NULL } },
{ { "dst" }, DSTCommand, { NULL } },
#endif
(snip...)
|
...which I don't 100% understand, but I'm assuming is a workaround for pointers to consts? (which are still not supported)
To me, the above looks like you're embedding some form of lookup table directly into the ROM (potentially trying to avoid excessive use of RAM?) - and the struct defines a pointer to a function directly from what I can see - so you're assuming that there is support for pointers to functions now (?).
So while this is a long shot - would I be right in assuming that by using the structure of the above bit of code - I would somehow be able to define my entire menu structure directly including parent/child relationships/menutext on the ROM without running out of RAM?
Or have I completely missed the point and I should turn bright red and hide now?
Thanks copiously..
//ak. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Oct 17, 2005 2:16 pm |
|
|
Quote: | I did indeed - and was wondering whether this was still valid or not - as it appears to be trying to overcome the limitation regarding pointers to functions - which - according to the version/changes log - is now supported as of 3.160 directly without having to go use your workaround?
| The code does use function pointers.
Quote: | /*****************************************************************************
This is an example of how to create a const array of function
pointers and call them. It is a bit of a trick to fool the compiler
but seems to work for the cases that I tested.
******************************************************************************/ |
It just allows you to store them in ROM instead of wasting RAM
The other post is for another compiler which does allow pointers to constants which make things nice. It will not work for CCS |
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
|
Posted: Mon Oct 17, 2005 2:29 pm |
|
|
Mark wrote: |
It just allows you to store them in ROM instead of wasting RAM
The other post is for another compiler which does allow pointers to constants which make things nice. It will not work for CCS |
Got it.
However, in that particular post - you refer to an address directly:
Code: |
#define MENU_START_ADDRESS 0x200
|
How did you decide on this particular address to start with? Is this arbitrary?
Although while efficient - with 200 menu items, I can see that this is going to get quite hairy.
//ak. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Oct 17, 2005 2:33 pm |
|
|
Quote: | How did you decide on this particular address to start with? | It looked pretty
It was near the start of program memory but allowed room for the ISR handler. I don't think it really mattered that much.
Quote: | Although while efficient - with 200 menu items, I can see that this is going to get quite hairy.
| Cut and Paste |
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
|
Posted: Mon Oct 17, 2005 2:40 pm |
|
|
Quote: | /*****************************************************************************
This is an example of how to create a const array of function
pointers and call them. It is a bit of a trick to fool the compiler
but seems to work for the cases that I tested.
******************************************************************************/ |
Also, from another post - you mention:
Quote: |
I create a const data struct that contains many things about a menu entry. What to do if you press a certain button (function pointers), menu text, ...., and the "parent menu" id. With this, there is no need to save the current state since you will know where to go when the user hits the back or up button. |
I don't suppose you can give me an example of what you mean here showing the struct and one or two definitions of menu items?
Thanks again..
//ak. |
|
|
kanemoto
Joined: 17 Oct 2005 Posts: 6
|
|
Posted: Mon Oct 17, 2005 2:42 pm |
|
|
Mark wrote: | Quote: | How did you decide on this particular address to start with? | It looked pretty
It was near the start of program memory but allowed room for the ISR handler. I don't think it really mattered that much.
Quote: | Although while efficient - with 200 menu items, I can see that this is going to get quite hairy.
| Cut and Paste |
*grin*
//ak. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Oct 17, 2005 2:46 pm |
|
|
Keep in mind that this is not for the CCS compiler.
Code: |
PTR_ROM PHASE_HELP[] =
{
"Set the phase of the",
"power feeding this",
"device to enable",
"zero cross switching",
"of the relays",
"Press EDIT to change",
NULL
};
enum menus
{
m_NULL, /* Just so the first real Menu is not 0 */
m_Main,
m_Menu,
m_Events,
m_Holidays,
m_Inputs,
m_Remotes,
m_Relays,
m_Masks,
m_TimeDate,
m_CabinetPhase,
m_Location,
m_DiagnosticMenu,
m_Sun,
m_Reinit,
m_Password,
m_PassEntry,
m_About,
m_SwitchStatus,
m_PhotoStatus,
m_RelayStatus,
m_RelayFlash,
m_SettingsMenu,
m_Comm,
m_InputNoRelayLink,
m_InputInvalidWarn,
m_EventNoRelayLink,
m_EventNoDayLink,
m_MaskInvalidTime,
m_MaskNoInputLink,
m_MaskNoDayLink,
m_RemoteNoRelayLink,
m_NetworkStatus,
m_LastMenu /* just so we know where the last menu is */
};
typedef rom struct _menu
{
enum menus menu;
enum menus parentmenu;
rom const char *pStr;
PTR_ROM *pViewHelp;
PTR_ROM *pEditHelp;
void (*Soft_Key) (signed char index); /* command function */
void (*Up_Key) (signed char index); /* command function */
void (*Down_Key) (signed char index); /* command function */
void (*Left_Key) (signed char index); /* command function */
void (*Right_Key) (signed char index); /* command function */
void (*Input_Key) (signed char index); /* command function */
void (*Relay_Key) (signed char index); /* command function */
void (*Day_Key) (signed char index); /* command function */
void (*Menu_Key) (signed char index); /* command function */
void (*Display_Menu) (void); /* command function */
}MENU;
/* Below are menu entries. Each menu must have an entry with the defined
* fields. */
MENU MENU_NETWORK_STATUS =
{
m_NetworkStatus, /* MenuID */
m_DiagnosticMenu, /* Parent Menu */
" COMM STATUS", /* Menu Text */
NULL, /* View Help Text */
NULL, /* Edit Help Text */
Net_Status_Softkey, /* Softkey */
NULL, /* Upkey */
NULL, /* Downkey */
NULL, /* Leftkey */
NULL, /* Rightkey */
NULL, /* Inputkey */
NULL, /* Relaykey */
NULL, /* Daykey */
Default_Menukey, /* Menukey */
DisplayNetStatusMenu /* Display function */
};
MENU MENU_PASSWORD_ENTRY =
{
m_PassEntry, /* MenuID */
m_SettingsMenu, /* Parent Menu */
" PASSWORD", /* Menu Text */
PASS_HELP, /* View Help Text */
E_PASS_HELP, /* Edit Help Text */
PassEntry_Softkey, /* Softkey */
Pass_Upkey, /* Upkey */
Pass_Downkey, /* Downkey */
Pass_Leftkey, /* Leftkey */
Pass_Rightkey, /* Rightkey */
Pass_Inputkey, /* Inputkey */
NULL, /* Relaykey */
NULL, /* Daykey */
Default_Menukey, /* Menukey */
DisplayPassEntry /* Display function */
};
MENU MENU_SETTINGS_MENU =
{
m_SettingsMenu, /* MenuID */
m_Menu, /* Parent Menu */
" SETTINGS", /* Menu Text */
NULL, /* View Help Text */
NULL, /* Edit Help Text */
Menu_Softkey, /* Softkey */
Menu_Upkey, /* Upkey */
Menu_Downkey, /* Downkey */
Menu_Leftkey, /* Leftkey */
Menu_Rightkey, /* Rightkey */
NULL, /* Inputkey */
NULL, /* Relaykey */
NULL, /* Daykey */
Default_Menukey, /* Menukey */
DisplaySelectMenu /* Display function */
};
MENU MENU_ABOUT =
{
m_About, /* MenuID */
m_DiagnosticMenu, /* Parent Menu */
" ABOUT", /* Menu Text */
NULL, /* View Help Text */
NULL, /* Edit Help Text */
Default_Menukey, /* Softkey */
NULL, /* Upkey */
NULL, /* Downkey */
NULL, /* Leftkey */
NULL, /* Rightkey */
NULL, /* Inputkey */
NULL, /* Relaykey */
NULL, /* Daykey */
Default_Menukey, /* Menukey */
DisplayAboutMenu /* Display function */
};
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|