Skip to content

Instantly share code, notes, and snippets.

@jpearman
Created November 30, 2016 04:51
Show Gist options
  • Save jpearman/95769ea3cf70181cf6fc62a81fb9e666 to your computer and use it in GitHub Desktop.
Save jpearman/95769ea3cf70181cf6fc62a81fb9e666 to your computer and use it in GitHub Desktop.
#pragma config(UART_Usage, UART2, uartVEXLCD, baudRate19200, IOPins, None, None)
//*!!Code automatically generated by 'ROBOTC' configuration wizard !!*//
/*-----------------------------------------------------------------------------*/
/* */
/* Module: menuDemo.c */
/* Author: James Pearman */
/* Created: 25 August 2012 */
/* */
/* Revisions: V0.1 */
/* */
/*-----------------------------------------------------------------------------*/
/* */
/* Description: */
/* */
/* Demo for ROBOTC 3.5 (3.45 beta) pointers */
/* This version updated and tested with RobotC V4.55, 29 Nov 2016 */
/*-----------------------------------------------------------------------------*/
/* */
//
// There are a couple of issues with the beta release of ROBOTC 3.5
// functions cannot return pointers to complex types, this is why I return
// int * in some functions but then cast to the real pointer type later on.
//
// There is no automatic cast to pointer for complex variables, this means that
// structs need an explicit & sign to use as a pointer, normaly this would not
// be needed.
//
// There is an issue with forward declaration so these are defined
// here so they can be used in the real structures as variables
//
struct _clist;
struct _menu;
struct _menuList;
// Different types of menus
#define MENUTYPE_VALUE 0
#define MENUTYPE_CHOICE 1
#define MENUTYPE_SUB 2
#define MENUTYPE_EXIT 99
// Default for LCD line 2 display
#define DEFAULT_LINE2 "<< >>"
#define SUBMENU_SELECT_TEXT "<< SELECT >>"
#define EXIT_MENU_SELECT "<< OK >>"
// A menu list
// holds a double linked list of menus
typedef struct _menuList {
// number of menus in this list
int num;
// pointer to first menu
struct _menu *first;
// pointer to last menu
struct _menu *last;
// pointer to current menu
struct _menu *current;
} menuList;
// A menu structure
typedef struct _menu {
// lcd display text
char lcd_line_1[20];
char lcd_line_2[20];
// pointes to next and previous menus
struct _menu *next;
struct _menu *prev;
// the type of this menu
int menu_type;
// value (used as index for choice menus)
int value;
// maximum value of a "value" menu
int max_value;
// list of choices
int cnum;
struct _clist *cfirst;
struct _clist *cend;
// pointer to a menu list - a sub menu
menuList *list;
} menu;
// A choice structure
typedef struct _clist {
// name of choice
char name[20];
// pointer to next choice
struct _clist *next;
// pointer to previous choice
struct _clist *prev;
} clist;
// Enums for button pushes in the menu state machine
typedef enum _userControl {
initializeButton = 0,
noButton,
leftButtonDown,
rightButtonDown,
centerButtonDown
} userControl;
// Storage for our menus, choices and lists
// We use this instead of dynamic memory allocation as it is not available
#define MAX_MEN_LISTS 4
menuList Lists[MAX_MEN_LISTS];
#define MAX_MENUS 10
menu Menus[MAX_MENUS];
#define MAX_CHOICES 10
clist MenuChoices[MAX_CHOICES];
// Indexes for next item to be allocated
static int nl = 0;
static int nm = 0;
static int nc = 0;
/*-----------------------------------------------------------------------------*/
/* */
/* Create a new menu list */
/* */
/*-----------------------------------------------------------------------------*/
menuList *
menuListInit( )
{
menuList *list;
list = &(Lists[nl++]);
list->first = NULL;
list->last = NULL;
list->num = 0;
return(list);
}
/*-----------------------------------------------------------------------------*/
/* */
/* Add a menu to a menu list */
/* */
/*-----------------------------------------------------------------------------*/
int
menuListAddMenu( menuList *list, menu *m )
{
menu *TopMenu;
menu *EndMenu;
// check for valid list
if( list == NULL )
return(-1);
// check for valid menu
if( m == NULL )
return(-2);
if( list->num == 0 )
{
// first entry
list->first = m;
list->last = m;
// double linked list that we want to rate so pint at ourself
m->next = (menu *)m;
m->prev = (menu *)m;
}
else
{
// get the menus at start and end of the list
TopMenu = list->first;
EndMenu = list->last;
// Add to end of list
m->prev = EndMenu;
m->next = list->first;
// relink the list
EndMenu->next = m;
TopMenu->prev = m;
// this menu is now the last one
list->last = m;
}
// make new menu current menu
list->current = m;
// one more entry
list->num++;
return( list->num );
}
/*-----------------------------------------------------------------------------*/
/* */
/* Initialize a menu and link into the menu list */
/* */
/*-----------------------------------------------------------------------------*/
menu *
menuInit( menuList *list, const char *name, int type, int max )
{
menu *m;
// We have no malloc so use allocate from an array
m = &(Menus[nm++]);
// LCD line 1 display
sprintf( &(m->lcd_line_1[0]), "%s", name );
// Default for LCD line 2 display
switch(type)
{
case MENUTYPE_SUB:
sprintf( &(m->lcd_line_2[0]), SUBMENU_SELECT_TEXT );
break;
case MENUTYPE_EXIT:
sprintf( &(m->lcd_line_2[0]), EXIT_MENU_SELECT );
break;
default:
sprintf( &(m->lcd_line_2[0]), DEFAULT_LINE2 );
break;
}
// note menu type
m->menu_type = type;
// default values
m->value = 0;
m->max_value = max;
// no choices yet
m->cfirst = NULL;
m->cend = NULL;
m->cnum = 0;
// no sub menu yet
m->list = NULL;
// link into list
menuListAddMenu( list, m );
// return pointer to this menu
return(m);
}
/*-----------------------------------------------------------------------------*/
/* */
/* Add one choice to a menu */
/* */
/*-----------------------------------------------------------------------------*/
clist *
MenuAddChoice( menu *m, const char *name )
{
clist *c;
clist *end;
// check for null pointer
if( m == NULL )
return(NULL);
// We have no malloc so use allocate from an array
c = &(MenuChoices[nc++]);
// first choice
if(m->cnum == 0)
{
m->cfirst = c;
m->cend = c;
c->prev = (clist *)NULL;
c->next = (clist *)NULL;
}
else
{
// subsequent choices
end = m->cend;
// only link to end - this list is not circular
m->cend = c;
end->next = c;
c->prev = end;
c->next = (clist *)NULL;
}
// copy name for this choice
sprintf( &(c->name[0]), "%s", name );
// one more
m->cnum++;
// return pointer to the choice
return(c);
}
/*-----------------------------------------------------------------------------*/
/* */
/* Update the LCD display with the menu information */
/* */
/*-----------------------------------------------------------------------------*/
void
menuLcdUpdate( menu *m )
{
clearLCDLine(0);
clearLCDLine(1);
displayLCDString(0, 0, m->lcd_line_1);
displayLCDString(1, 0, m->lcd_line_2);
}
/*-----------------------------------------------------------------------------*/
/* */
/* Create a value display for the LCD line 2 */
/* */
/*-----------------------------------------------------------------------------*/
void
menuCreateValueDisplay( menu *m )
{
sprintf( &(m->lcd_line_2[0]), "<< %04d >>", m->value);
}
/*-----------------------------------------------------------------------------*/
/* */
/* Create a choice display for the LCD line 2 */
/* */
/*-----------------------------------------------------------------------------*/
void
menuCreateChoiceDisplay( menu *m )
{
int i;
clist *c;
int len;
// NULL pointer checks
if( m == NULL )
return;
// Find choice in list
if( (c = m->cfirst) == NULL )
return;
// move through list to find indexd choice
// inefficient for a large number of choices but ok for this demo
for(i=0;i<m->value;i++)
{
if( c->next != NULL)
c = c->next;
}
// get length of choice
len = strlen( &(c->name[0]) );
// Make string with the arrows at each end
sprintf( &(m->lcd_line_2[0]), "<< >>" );
// len needs to be 12 or less
if(len > 12)
len = 12;
// overlay choice to display
for( i=0;i<len; i++)
m->lcd_line_2[2 + (6-(len+1)/2) + i] = c->name[i];
}
/*-----------------------------------------------------------------------------*/
/* */
/* Update the text for the LCD line 2 based on the menu type */
/* */
/*-----------------------------------------------------------------------------*/
void
menuCreateDisplay( menu *m )
{
if( m->menu_type == MENUTYPE_VALUE )
menuCreateValueDisplay( m );
else
if( m->menu_type == MENUTYPE_CHOICE )
menuCreateChoiceDisplay( m );
}
/*-----------------------------------------------------------------------------*/
/* */
/* Run a menu list */
/* */
/*-----------------------------------------------------------------------------*/
int
menuRun( menuList *list )
{
bool done = false;
int LcdButtons;
userControl buttonState = initializeButton;
while( !done )
{
// Read LCD buttons
LcdButtons = nLCDButtons;
switch( buttonState )
{
case initializeButton:
case leftButtonDown:
case rightButtonDown:
case centerButtonDown:
// Display select program
menuCreateDisplay( list->current );
menuLcdUpdate( list->current );
// Wait here until nothing is pressed
if( LcdButtons == 0 )
buttonState = noButton;
break;
case noButton:
// Check left button
if( LcdButtons & kButtonLeft )
{
buttonState = leftButtonDown;
// previous menu
if( list->current->prev != NULL )
list->current = list->current->prev;
}
// Check right button
if( LcdButtons & kButtonRight )
{
buttonState = rightButtonDown;
// next menu
if( list->current->next != NULL )
list->current = list->current->next;
}
// Check center button
if( LcdButtons & kButtonCenter )
{
buttonState = centerButtonDown;
switch( list->current->menu_type )
{
case MENUTYPE_EXIT:
// An exit menu - we are done
done = true;
break;
case MENUTYPE_VALUE:
// simle menu with a variable
// increase value
list->current->value++;
// check for max and wrap around
if( list->current->value > list->current->max_value )
list->current->value = 0;
break;
case MENUTYPE_CHOICE:
// Menu with a list of choices
// value is used as an index
list->current->value++;
// check for end of choice list and wrap
if( list->current->value >= list->current->cnum )
list->current->value = 0;
break;
case MENUTYPE_SUB:
// selection using a sub menu
if( list->current->list != NULL )
{
// recursively enter menu run for sub menu
menuRun( list->current->list );
// now change the menu name to match the selection
strcpy( list->current->lcd_line_1, list->current->list->current->lcd_line_1 );
}
break;
default:
break;
}
}
break;
default:
// why are we here ??
buttonState = noButton;
break;
}
// 50mS Delay
wait1Msec(50);
}
return(0);
}
/*-----------------------------------------------------------------------------*/
/* */
/* Demo code */
/* */
/*-----------------------------------------------------------------------------*/
task main() {
menuList *mainMenu;
menuList *autonomousSubMenu;
menu *m;
bLCDBacklight = true;
mainMenu = menuListInit( );
autonomousSubMenu = menuListInit( );
// Alliance selection menu
m = menuInit( mainMenu, "Alliance", MENUTYPE_CHOICE, 0 );
MenuAddChoice( m, "RED" );
MenuAddChoice( m, "BLUE" );
// Autonomous menu - has sub menu
m = menuInit( mainMenu, "Auto Wall 1", MENUTYPE_SUB, 0 );
m->list = autonomousSubMenu;
// Sub menu for autonomous selection
menuInit( autonomousSubMenu, "Auto Special", MENUTYPE_EXIT, 0 );
menuInit( autonomousSubMenu, "Auto Floor A", MENUTYPE_EXIT, 0 );
menuInit( autonomousSubMenu, "Auto Wall 2", MENUTYPE_EXIT, 0 );
menuInit( autonomousSubMenu, "Auto Wall 1", MENUTYPE_EXIT, 0 );
// some nondescript variable with a maximum value of 10
menuInit( mainMenu, "Sensitivity", MENUTYPE_VALUE, 10 );
// An exit menu - Done and run code
menuInit( mainMenu, "Run Code", MENUTYPE_EXIT, 0 );
// Start menus
menuRun( mainMenu);
// menu system done so do something
clearLCDLine(0);
clearLCDLine(1);
displayLCDString(0, 0, "Code running");
int time = 0;
while(1)
{
char s[20];
sprintf(s, "time %.1f", (float)time/1000.0 );
displayLCDString(1, 0, s);
time += 100;
wait1Msec(100);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment