Having some issues with porting some code

Hello, I recently got a photon and I’ve been working on porting some of my code over from other micros I’ve used. I’m currently trying to get a little menu system I made ported over and I seem to be having some issues getting it working properly. This code works fine on the other boards I’ve used so its a little confusing.

The problem seems to be within the setFunc function. It doesn’t seem to update when changing menus. I have it setup to copy a function pointer array to the current_func array, I’ve tried a couple things and not had any luck. It seems to work one time and then not again. If anyone has any suggestions they would be greatly appreciated. I’ve posted all the code below. Thanks!

#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
#define TFT_DC D5
#define TFT_CS D4
#define TFT_MOSI A5
#define TFT_CLK A3
#define TFT_RST D6
#define TFT_MISO A4

#define up D3
#define down D2
#define select D1

#define UP 1
#define DOWN 2
#define SELECT 3

//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);


bool appRunning = false;
int selected; // currently selected menu item
int upButtonState = 0;
int downButtonState = 0;
int selectButtonState = 0;
char* current_menu[255] = {0};
uint8_t current_menu_index = 1; // current position in the array
uint8_t current_menu_size;
bool page_change = false;
uint8_t menu_top = 35; // top space between title and items

typedef void (* CurrentFuncPtr) (); // Function pointer for current menu
typedef void (* PassFuncPtr) (); // Function pointer for current menu
typedef void (* MenuFuncPtr) (); // Function pointer for Main Menu
typedef void (* Test1FuncPtr) (); // Function pointer for Test Menu 1
typedef void (* Test2FuncPtr) (); // Function pointer for Test Menu 2

// function prototypes
void setMenu(char** menu, uint8_t size);
void setFunc(PassFuncPtr* funcs, uint8_t size);
void buildTestMenu1(void);
void buildTestMenu2(void);
void returnMainMenu(void);

char* mainMenu[3] = {"    Main Menu",
                    "Test Menu 1   ",
                    "Test Menu 2   "
                   };

char* testMenu1[4] = {"   Test Menu 1",
                    "Option 1   ",
                    "Option 2   ",
                    "Back       "
                   };

char* testMenu2[4] = {"   Test Menu 2",
                    "Option 1   ",
                    "Option 2   ",
                    "Back       "
                   };


CurrentFuncPtr current_func[255] = {NULL};

// Main menu func pointer
MenuFuncPtr menu_func[3] = {NULL,
                            buildTestMenu1,
                            buildTestMenu2};
// Test menu Func Pointer
Test1FuncPtr test1_func[4] = {NULL,
                            buildTestMenu2,
                            buildTestMenu2,
                            returnMainMenu};

Test2FuncPtr test2_func[4] = {NULL,
                            buildTestMenu1,
                            buildTestMenu1,
                            returnMainMenu};


void setup() {
  Serial.begin(9600);

  // Button Setup
  pinMode(up, INPUT_PULLUP);

  pinMode(down, INPUT_PULLUP);

  pinMode(select, INPUT_PULLUP);

  tft.begin();
  tft.setTextWrap(false);
  tft.setRotation(3);
  tft.setTextSize(3);
  setMenu(mainMenu, sizeof(mainMenu)/sizeof(char *)-1);
  setFunc(menu_func, sizeof(menu_func)/sizeof(char *)-1);
  displayMenu();
}

void menuInput(void) {
  // read the state of the pushbutton value:
  upButtonState = digitalRead(up);
  downButtonState = digitalRead(down);
  selectButtonState = digitalRead(select);

  if (upButtonState == LOW) {
    // Up
    action(UP);
  }
  else if (downButtonState == LOW) {
    // Down
    action(DOWN);
  }
  else if (selectButtonState == LOW) {
    selected = returnSelected();
    action(SELECT);
  }
  delay(100);
}

void loop() {
  while(!appRunning) {
    menuInput();
  }
}

void returnMainMenu(void) {
  setMenu(mainMenu, sizeof(mainMenu)/sizeof(char *)-1);
  setFunc(menu_func, sizeof(menu_func)/sizeof(char *)-1);
  displayMenu();
}

void buildTestMenu1(void) {
  setMenu(testMenu1, sizeof(testMenu1)/sizeof(char *)-1);
  setFunc(test1_func, sizeof(test1_func)/sizeof(char *)-1);
  displayMenu();
}

void buildTestMenu2(void) {
  setMenu(testMenu2, sizeof(testMenu2)/sizeof(char *)-1);
  setFunc(test2_func, sizeof(test2_func)/sizeof(char *)-1);
  displayMenu();
}


void setMenu(char** menu, uint8_t size) {
  memset(current_menu, 0, size);
  int i;
  for(i=0; i<=size; i++) {
      current_menu[i] = menu[i];
  }
  selected = 1;
  current_menu_size = i-2;
}

void setFunc(PassFuncPtr* funcs, uint8_t size) {
  memset(current_func, 0, size);
  Serial.println(size);
  int i;
  for(i=0; i<=size; i++) {
      current_func[i] = funcs[i];
  }
}

void displayMenu(void) {
  int i;
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  tft.println(current_menu[0]);
  tft.drawLine(0, 25, tft.width()-1, 25, ILI9341_GREEN);

  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  for(i = current_menu_index; i <= (current_menu_index + 6); i++) {
      tft.setCursor(0, ((i - current_menu_index) * 30) + menu_top);
      tft.println(current_menu[i]);
  }
  menuHighlight(selected);
}

void menuHighlight(uint8_t index) {
  if (page_change == false) {
      tft.setCursor(0, ((selected - current_menu_index) * 30) + menu_top);
      tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
      tft.println(current_menu[selected]);
  }
  tft.setCursor(0, ((index - current_menu_index) * 30) + menu_top);
  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLUE);
  tft.println(current_menu[index]);
  selected = index;
  page_change = false;
}

int returnSelected(void) {
  return selected;
}

void action(uint8_t action) {
  switch (action) {
      case 1: { // up
          if (selected <= (current_menu_index + 6) && (selected > current_menu_index)) {
              menuHighlight(selected - 1);
          }
          else if ((current_menu_index > 1) && (selected <= current_menu_index)) {
              current_menu_index = (current_menu_index - 1);
              selected = selected - 1;
              page_change = true;
              displayMenu();
          }
          break;
      }
      case 2: { // down
          if (selected >= (current_menu_index + 6) &&
              (current_menu_size > 6) && (selected <= current_menu_size)) {
              current_menu_index = (current_menu_index + 1);
              selected = selected + 1;
              page_change = true;
              displayMenu();
          }
          else if ((selected < (current_menu_index + 6)) &&
                  (selected <= current_menu_size)) {
              menuHighlight(selected + 1);
          }
          break;
      }
      case 3: // select
          menu_func[selected]();//
          break;
  }
}

My problem isn’t with the ili9341 library, that seems to be working fine. Its a problem with my own little menu system code. I’m currently using that library in the code and it works. :slight_smile:

My Bad :slight_smile:

1 Like

It seems that I cant clear/write to the current_func after doing it the first time.

I can’t seem to wrap my head around your passing around all those function pointers, it seems a long winded choice.

I’d use structs for the data:

struct MenuText{
  char* line1;
  char* line2;
  char* line3;
  char* line4;
};

const MenuText mainMenu = {
  "    Main Menu",
  "Test Menu 1   ",
  "Test Menu 2   ",
  "",
};

const MenuText testMenu1 = {
  "   Test Menu 1",
  "Option 1   ",
  "Option 2   ",
  "Back       "
};

MenuText* currentMenu = &mainMenu;

void setup() {
  Serial.begin(9600);
  setMenu(currentMenu);
  currentMenu = &testMenu1;
  Serial.println();
  setMenu(currentMenu);
}

void loop() {
  // put your main code here, to run repeatedly:

}

void setMenu(MenuText* menu)
{
  Serial.println(menu->line1);
  Serial.println(menu->line2);
  Serial.println(menu->line3);
  Serial.println(menu->line4);
}

1 Like

Thanks for the input, I’ll try restructuring and give this a try. I’m not as familiar with function pointers so I wasn’t sure what the best way to handle it was.

One of the reasons I set it up that way was to make it so the menus could be variable length. Like reading files from an SD card.

I’m not really advocating… mainly because I couldn’t really understand why you went down the path as you did.

it’s just that I feel that if the menus are more or less fixed, I think managing the data (menu text) as an object(s) is more intuitive, and easier.

you can even add function pointers for your buttons to the menu struct:

using functPtr = void (*)(void);

void mainUpPressed(void);
void mainDownPressed(void);
void mainRightPressed(void);
void mainLeftPressed(void);

struct MenuText{
  char* line1;
  char* line2;
  char* line3;
  char* line4;
  functPtr upButton;
  functPtr downButton;
  functPtr rightButton;
  functPtr leftButton;
};


MenuText mainMenu = {
  "    Main Menu",
  "Test Menu 1   ",
  "Test Menu 2   ",
  "",
  mainUpPressed,
  mainDownPressed,
  mainRightPressed,
  mainLeftPressed,
};

// and so on...

you can dereference the function pointers similarly to above example…

3 Likes

I agree that with fixed data menus, your option seems much simpler. Maybe I can use a combination of both. Thanks again for the input, it’s definitely helping me think this out.

1 Like

I was able to track down my issue, I had one variable miss named menu_func[selected]();// should be current_func[selected];. Here is the complete working code if anyone needs a simple menu system.

#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
#define TFT_DC D5
#define TFT_CS D4
#define TFT_MOSI A5
#define TFT_CLK A3
#define TFT_RST D6
#define TFT_MISO A4

#define up D3
#define down D2
#define select D1

#define UP 1
#define DOWN 2
#define SELECT 3

//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

const int arraySize = 100;
bool appRunning = false;
int selected; // currently selected menu item
int upButtonState = 0;
int downButtonState = 0;
int selectButtonState = 0;
char* current_menu[arraySize] = {0};
uint8_t current_menu_index = 1; // current position in the array
uint8_t current_menu_size;
bool page_change = false;
uint8_t menu_top = 35; // top space between title and items

typedef void (* CurrentFuncPtr) (); // Function pointer for current menu
typedef void (* MenuFuncPtr) (); // Function pointer for Main Menu
typedef void (* Test1FuncPtr) (); // Function pointer for Test Menu 1
typedef void (* Test2FuncPtr) (); // Function pointer for Test Menu 2

// function prototypes
void setMenu(char** menu, CurrentFuncPtr* funcs, uint8_t size);
void buildTestMenu1(void);
void buildTestMenu2(void);
void returnMainMenu(void);

char* mainMenu[3] = {"    Main Menu",
                    "Test Menu 1   ",
                    "Test Menu 2   "
                   };

char* testMenu1[4] = {"   Test Menu 1",
                    "Option 1   ",
                    "Option 2   ",
                    "Back       "
                   };

char* testMenu2[4] = {"   Test Menu 2",
                    "Option 1   ",
                    "Option 2   ",
                    "Back       "
                   };


CurrentFuncPtr* current_func = NULL;

// Main menu func pointer
MenuFuncPtr menu_func[4] = {0,
                            buildTestMenu1,
                            buildTestMenu2};
// Test menu Func Pointer
Test1FuncPtr test1_func[5] = {0,
                            0,
                            0,
                            returnMainMenu};

Test2FuncPtr test2_func[5] = {0,
                            0,
                            0,
                            returnMainMenu};


void setup() {
  Serial.begin(9600);

  // Button Setup
  pinMode(up, INPUT_PULLUP);

  pinMode(down, INPUT_PULLUP);

  pinMode(select, INPUT_PULLUP);

  tft.begin();
  tft.setTextWrap(false);
  tft.setRotation(3);
  tft.setTextSize(3);
  setMenu(mainMenu, menu_func, sizeof(mainMenu)/sizeof(char *)-1);
  displayMenu();
}

void menuInput(void) {
  // read the state of the pushbutton value:
  upButtonState = digitalRead(up);
  downButtonState = digitalRead(down);
  selectButtonState = digitalRead(select);

  if (upButtonState == LOW) {
    // Up
    action(UP);
  }
  else if (downButtonState == LOW) {
    // Down
    action(DOWN);
  }
  else if (selectButtonState == LOW) {
    action(SELECT);
  }
  delay(100);
}

void loop() {
  while(!appRunning) {
    menuInput();
  }
}

void returnMainMenu(void) {
  setMenu(mainMenu, menu_func, sizeof(mainMenu)/sizeof(char *)-1);
  displayMenu();
}

void buildTestMenu1(void) {
  setMenu(testMenu1, test1_func, sizeof(testMenu1)/sizeof(char *)-1);
  displayMenu();
}

void buildTestMenu2(void) {
  setMenu(testMenu2, test2_func, sizeof(testMenu2)/sizeof(char *)-1);
  displayMenu();
}


void setMenu(char** menu, CurrentFuncPtr* funcs, uint8_t size) {
  memset(current_menu, 0, arraySize);

  current_func = funcs;
  int i;
  for(i=0; i<=size; i++) {
    current_menu[i] = menu[i];
  }
  selected = 1;
  current_menu_size = i-2;
}

void displayMenu(void) {
  int i;
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
  tft.println(current_menu[0]);
  tft.drawLine(0, 25, tft.width()-1, 25, ILI9341_GREEN);

  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
  for(i = current_menu_index; i <= (current_menu_index + 6); i++) {
      tft.setCursor(0, ((i - current_menu_index) * 30) + menu_top);
      tft.println(current_menu[i]);
  }
  menuHighlight(selected);
}

void menuHighlight(uint8_t index) {
  if (page_change == false) {
      tft.setCursor(0, ((selected - current_menu_index) * 30) + menu_top);
      tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
      tft.println(current_menu[selected]);
  }
  tft.setCursor(0, ((index - current_menu_index) * 30) + menu_top);
  tft.setTextColor(ILI9341_YELLOW, ILI9341_BLUE);
  tft.println(current_menu[index]);
  selected = index;
  page_change = false;
}

void action(uint8_t action) {
  switch (action) {
      case 1: { // up
          if (selected <= (current_menu_index + 6) && (selected > current_menu_index)) {
              menuHighlight(selected - 1);
          }
          else if ((current_menu_index > 1) && (selected <= current_menu_index)) {
              current_menu_index = (current_menu_index - 1);
              selected = selected - 1;
              page_change = true;
              displayMenu();
          }
          break;
      }
      case 2: { // down
          if (selected >= (current_menu_index + 6) &&
              (current_menu_size > 6) && (selected <= current_menu_size)) {
              current_menu_index = (current_menu_index + 1);
              selected = selected + 1;
              page_change = true;
              displayMenu();
          }
          else if ((selected < (current_menu_index + 6)) &&
                  (selected <= current_menu_size)) {
              menuHighlight(selected + 1);
          }
          break;
      }
      case 3: // select
          current_func[selected]();//
          break;
  }
}
1 Like