CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Menus: linked lists, case/switch, function pointers?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kanemoto



Joined: 17 Oct 2005
Posts: 6

View user's profile Send private message

Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 1:00 am     Reply with quote

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.. Smile


//ak.
kender



Joined: 09 Aug 2004
Posts: 768
Location: Silicon Valley

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

Re: Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 1:23 am     Reply with quote

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

View user's profile Send private message

Re: Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 2:29 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

Re: Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 2:40 am     Reply with quote

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

View user's profile Send private message

Re: Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 3:26 am     Reply with quote

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? Smile

//ak.
kanemoto



Joined: 17 Oct 2005
Posts: 6

View user's profile Send private message

Re: Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 4:03 am     Reply with quote

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: 1636
Location: Perth, Australia

View user's profile Send private message Send e-mail Visit poster's website

Re: Menus: linked lists, case/switch, function pointers?
PostPosted: Mon Oct 17, 2005 6:49 am     Reply with quote

[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

View user's profile Send private message Send e-mail

PostPosted: Mon Oct 17, 2005 8:03 am     Reply with quote

Did you come across this?

http://www.ccsinfo.com/forum/viewtopic.php?t=20416&start=15
kanemoto



Joined: 17 Oct 2005
Posts: 6

View user's profile Send private message

PostPosted: Mon Oct 17, 2005 2:11 pm     Reply with quote

Mark wrote:
Did you come across this?

http://www.ccsinfo.com/forum/viewtopic.php?t=20416&start=15


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? Smile

Thanks copiously..

//ak.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon Oct 17, 2005 2:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 17, 2005 2:29 pm     Reply with quote

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. Smile


//ak.
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon Oct 17, 2005 2:33 pm     Reply with quote

Quote:
How did you decide on this particular address to start with?
It looked pretty Razz

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

View user's profile Send private message

PostPosted: Mon Oct 17, 2005 2:40 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 17, 2005 2:42 pm     Reply with quote

Mark wrote:
Quote:
How did you decide on this particular address to start with?
It looked pretty Razz

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

View user's profile Send private message Send e-mail

PostPosted: Mon Oct 17, 2005 2:46 pm     Reply with quote

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 */
};
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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