Scrolling Command Screen

Hi good people.

I have a problem which I can't find a solution to anywhere, and hope you can help.
Currently using an Arduino Mega 2560 with an ILI9486 tft.

It's running a program where users can type in commands, via command keys with preset commands ("Track", "Title", "Print" etc). There are five lines of command text shown, with the first four being the historical commands executed, and the fifth being the current one being written before execuion.

Each time a user hits "EXECUTE", I need the command text lines to move up the screen - the oldest will disappear, but it seems to be over-writing the others in the array. I've tried this scrolling by making the first "string" line equal to the second, then the second equal to the third etc, etc... then set the "ready command" string commandString[4] to show the ready symbol "#".

As the program runs, each of the strings in the commandString[] array, become the same as the last entered commands. All are over-writing each other.

I'm new in to the Arduino language, but have a strong historical background in Basic and VB.

Any help is much appreciated, as I have spent days on this with no success.

char buff[60];
char *commandString[5] = {"Hello", "Welcome to the program", "System ready", "Please enter first commands", "#"};
char *commandWords[25] = {"Print", "Join", "Name", "Revise", "Copy", "List", "Go To", "Play", "Cycle", "Delete", "Title", "Mix", "Cue", "Event", "Drop In", "Setup", "Preset", "Reel", "Track", "Sync", "End", "From", "Here", "To", "At"};

void touchScanCommandKeyboard() { //Check which command key has been pressed and update commandString[5]
  for (int j = 0; j < 5; j++) { //Scan through keys to see which commands have been pressed. 5x5 keyboard array.
    for (int i = 0; i < 5; i++) {
      if (px >= 66 + (i * 50) && px <= 66 + (i * 50) + 49 && py <= 320 - (44 + (j * 50)) && py >= 320 - (44 + (j * 50) + 49)) {

        strcpy(buff, commandString[4]); //Copy commandString[4] to the buffer
        strcat(buff, commandWords[(i) + (j * 5)]); //Concatenate the new command to the buffer
        strcat(buff, " "); //Add a space
        my_lcd.Print_String(buff, 72, 20); //Print to screen
        commandString[4] = buff; //Copy the buffer back in to commandString[4]
        delay(200);
      }
    }
  }
  if (px >= 360 && px <= 439 && py <= 76 && py >= 37) { //EXECUTE KEY HAS BEEN PRESSED
    scrollCommandText();
  }
}

void scrollCommandText() { //SCROLL UP TEXT
  for (int i = 0; i < 4; i++) {
    commandString[i] = commandString[i + 1]; //Shift up one line in the array
  }

  commandString[4] = "#"; //Display "INPUT READY" character

  drawFillRectangle(0, 0, 220, 51, BLACK); // Blank out command line area and write the five command lines.
  drawTextString(commandString[0], 0, 0, GREEN, BLACK);
  drawTextString(commandString[1], 0, 10, GREEN, BLACK);
  drawTextString(commandString[2], 0, 20, GREEN, BLACK);
  drawTextString(commandString[3], 0, 30, GREEN, BLACK);
  drawTextString(commandString[4], 0, 40, GREEN, BLACK);


}

Welcome to the forum and thank you for using code tags when you posted your code, but please post a complete sketch rather than a snippet so that it can be seen in context

Thanks for the reply. It’s part of a massive program, so only posted the critical parts.
I’ll try to trim it down, removing the unnecessary parts.

Anthony.

It's part of a massive program, so only posted the critical parts

Whilst you may think that what you are the critical parts that may not be the case. For instance, a classic problem is the declaration of global and local variables with the same name which is not visible unless a complete sketch is posted

Creating a minimal but complete example program is a good idea

OK here goes. It's over 9000 characters long, so might have to break it up.

// IMPORTANT: LCDWIKI_KBV LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.

#include <LCDWIKI_GUI.h> //Core graphics library
#include <LCDWIKI_KBV.h> //Hardware-specific library
#include <LCDWIKI_TOUCH.h>
#include "font.h"


LCDWIKI_KBV my_lcd(ILI9486, 40, 38, 39, 44, 41); //model,cs,cd,wr,rd,reset
LCDWIKI_TOUCH my_touch(53, 52, 50, 51, 44); //tcs,tclk,tdout,tdin,tirq

#define BLACK         0x0000
#define BLUE          0x001F
#define LIGHTBLUE     0x010D
#define RED           0xF800
#define GREEN         0x07E0
#define DARKGREEN     0x0700
#define CYAN          0x07FF
#define MAGENTA       0xF81F
#define ORANGE        0xFF00
#define YELLOW        0xFFC0
#define WHITE         0xFFFF




int shX = 30;
int shY = 0;
float sFc = 1.3;
int trZoom = 0;

char buff[60];
char *commandString[5] = {"Hello", "Welcome to the program", "System ready", "Please enter first commands", "#"};
char *commandWords[25] = {"Print", "Join", "Name", "Revise", "Copy", "List", "Go To", "Play", "Cycle", "Delete", "Title", "Mix", "Cue", "Event", "Drop In", "Setup", "Preset", "Reel", "Track", "Sync", "End", "From", "Here", "To", "At"};
char *commandKeyboardString[25] = {" PRINT", " JOIN", " NAME", "REVISE", " COPY", " LIST", " GO TO", " PLAY", " CYCLE", "DELETE", " TITLE", "  MIX", "  CUE", " EVENT", "DROP IN", "SET UP", "PRESET", " REEL", " TRACK", " SYNC", "  END", " FROM", " HERE", "  TO", "  AT"};
char *keypadString[50] = {"!", "''", "#", "?", "&", "+", "-", "(", ")", ":", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G", "H", "J", "K", "L", "*", "Z", "X", "C", "V", "B", "N", "M", "'", ".", " "};

int knobX[30] = {19, 19, 19, 82, 109, 82, 109, 82, 82, 109, 82, 146, 173, 146, 173, 146, 146, 173, 146, 173, 146, 209, 209, 209, 209, 209, 209, 209, 301, 301};
int knobY[30] = {130, 156, 182, 15, 33, 51, 69, 87, 121, 169, 182, 15, 30, 44, 59, 73, 102, 116, 131, 146, 160, 15, 42, 69, 96, 123, 150, 182, 121, 159};
int knobCol[30] = {BLUE, BLUE, RED, BLUE, BLUE, BLUE, DARKGREEN, DARKGREEN, DARKGREEN, BLUE, BLUE, RED, RED, DARKGREEN, DARKGREEN, DARKGREEN, BLUE, BLUE, BLUE, ORANGE, ORANGE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, RED, BLUE, BLUE};
int knobPosX[25] = { -5, -6, -7, -7, -7, -7, -7, -6, -5, -3, -2, -1, 0, 1, 2, 3, 5, 6, 7, 7, 7, 7, 7, 6, 5};
int knobPosY[25] = { -5, -3, -2, -1, 0, 1, 2, 3, 5, 6, 6, 7, 7, 7, 6, 6, 5, 3, 2, 1, 0, -1, -2, -3, -5};
int routingButton[72] = {6, 8, 21, 8, 36, 8, 51, 8, 6, 20, 21, 20, 36, 20, 51, 20, 6, 32, 21, 32, 36, 32, 51, 32, 6, 44, 21, 44, 36, 44, 51, 44, 6, 56, 21, 56, 36, 56, 51, 56, 6, 68, 21, 68, 36, 68, 51, 68, 6, 80, 21, 80, 36, 80, 51, 80, 6, 92, 21, 92, 36, 92, 51, 92, 6, 104, 21, 104, 36, 104, 51, 104};
int switchButton[58] = {39, 125, 39, 145, 39, 158, 39, 171, 39, 184, 102, 6, 102, 87, 102, 182, 166, 6, 166, 76, 166, 89, 166, 160, 229, 17, 229, 30, 229, 58, 229, 71, 229, 85, 229, 98, 229, 112, 229, 125, 229, 139, 229, 152, 229, 171, 229, 184, 293, 60, 293, 73, 293, 86, 293, 99, 293, 133};
int dyneqButton[12] = {74, 139, 90, 139, 106, 139, 138, 177, 154, 177, 170, 177};
int eaoSwitch[12] = {262, 4, ORANGE, 291, 4, DARKGREEN, 262, 174, YELLOW, 291, 174, RED};

int knobSetVal[30] = {0, 0, 150, 0, 0, 0, 100, 0, 0, 0, 0, 0, 700, 700, 0, 0, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 256};
int knobTempVal[30] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int knobCurVal[30] = {500, 500, 500, 500, 500, 500, 500, 500, 500, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50};

int routingButtonSetVal[36] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int routingButtonTempVal[36] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int routingButtonCurVal[36] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

int switchButtonSetVal[29] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int switchButtonTempVal[29] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int switchButtonCurVal[29] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

int dyneqButtonSetVal[6] = {0, 0, 0, 0, 0, 0};
int dyneqButtonTempVal[6] = {0, 0, 0, 0, 0, 0};
int dyneqButtonCurVal[6] = {0, 0, 0, 0, 0, 0};

int eaoSwitchSetVal[4] = {0, 0, 0, 0};
int eaoSwitchTempVal[4] = {0, 0, 0, 0};
int eaoSwitchCurVal[4] = {0, 0, 0, 0};

int smallFaderSetVal = 0;
int smallFaderTempVal = 0;
int smallFaderCurVal = 50;

int knobThresh = 4;
int knobPos = 0;
int routingThresh = 5;
int faderThresh = 5;
int dyneqThresh = 5;
int eaoThresh = 5;
int activeItem = 1;
int activeCursor = 1;

int screen = 1;
int prevScreen = 1;
int screenSaver = 0;
long screenSaverCount = 0;
int screenCommandKeyboard = 0;
int screenKeypadFlag = 0;

uint16_t px, py;

boolean is_pressed(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t px, int16_t py)
{
  if ((px > x1 && px < x2) && (py > y1 && py < y2))
  {
    return true;
  }
  else
  {
    return false;
  }
}

void setup() { //---------------------------------------------------setup----------------------------------------------------------

  my_lcd.Init_LCD();
  my_lcd.Set_Rotation(1);
  my_touch.TP_Init(3, 479, 319);
  my_lcd.Set_Text_Size(1);
  my_lcd.Set_Text_Mode(0);
  my_lcd.Set_Text_colour(GREEN);
  my_lcd.Set_Text_Back_colour(BLACK);
  my_lcd.Fill_Screen(BLACK);

  for (int i = 0; i < 30; i++) {
    knobCurVal[i] = knobTempVal[i];
  }

  screenSplash();
  splashLoading();
  screenHeader();
  screenList();
  my_lcd.Set_Text_Size(2);
  my_lcd.Set_Text_colour(GREEN);
  my_lcd.Set_Text_Back_colour(BLACK);
  my_lcd.Print_String(">", 460, 300);
  my_lcd.Set_Text_Size(1);

}



void loop() { //---------------------------------------------------loop----------------------------------------------------------

  px = 0;
  py = 0;
  my_touch.TP_Scan(0);
  if (my_touch.TP_Get_State()&TP_PRES_DOWN)
  {
    px = my_touch.x;
    py = my_touch.y;
    screenSaverCount = 0;
    if (screenSaver == 1) { //RELAUNCH LAST SCREEN IF IN SCREENSAVER MODE
      shX = 30;
      shY = 0;
      sFc = 1.333;
      trZoom = 0;
      switchScreen();
      screenSaver = 0;
    }
    else {
      touchedScreen();
    }
  }

  screenSaverCount = screenSaverCount + 1;

  if (screenSaverCount >= 10000000 && screenSaver == 0) {
    screenSplash();
    screenSaver = 1;
  }

}
void touchedScreen() { //----------------------------------------- touchedScreen -----------------------------------------------
  if (is_pressed(0, 0, 39, 39, px, py) && screenKeypadFlag == 0  && screenCommandKeyboard == 0 && trZoom == 0) { //OPEN PREVIOUS SCREEN
    screen = screen - 1;
    if (screen == 0) {
      screen = 1;
    }
    else
    {
      switchScreen();
    }
  }

  if (is_pressed(440, 0, 479, 39, px, py) && screenKeypadFlag == 0  && screenCommandKeyboard == 0) { //OPEN NEXT SCREEN
    screen = screen + 1;
    if (screen == 5) {
      screen = 4;
    }
    else
    {
      switchScreen();
    }
  }

  if (is_pressed(0, 260, 250, 319, px, py) && screenKeypadFlag == 0  && screenCommandKeyboard == 0 && prevScreen != 4) { //OPEN KEYPAD ON SCREEN
    commandKeyboard();
    delay(50);
  }

  if (is_pressed(0, 280, 39, 319, px, py) && screenCommandKeyboard == 1) { //SWITCH TO KEYPAD FROM COMMAND KEYBOARD
    screenKeypad();
    screenCommandKeyboard = 0;
  }

  else if (is_pressed(0, 280, 39, 319, px, py) && screenKeypadFlag == 1) { //SWITCH TO COMMAND KEYBOARD FROM KEYPAD
    commandKeyboard();
    screenKeypadFlag = 0;
  }

  if (is_pressed(440, 280, 479, 319, px, py) && screenCommandKeyboard == 1) { //CLOSE COMMAND KEYBOARD
    switchScreen();
    screenCommandKeyboard = 0;
  }
  else if (is_pressed(440, 280, 479, 319, px, py) && screenKeypadFlag == 1) { //CLOSE KEYPAD
    switchScreen();
    screenKeypadFlag = 0;
  }

  if (is_pressed(36, 33, 443, 280, px, py) && screenKeypadFlag == 1) { //CHECK WHICH KEYPAD KEY IS PRESSED
    touchScanKeypad();
  }

  if (is_pressed(62, 24, 419, 280, px, py) && screenCommandKeyboard == 1) { //CHECK WHICH KEYBOARD KEY IS PRESSED
    touchScanCommandKeyboard();
  }

  if (is_pressed(30, 54, 425, 319, px, py) && screen == 4 && trZoom == 0) { //ZOOM TOTAL RECALL
    shX = 0;
    shY = 0;
    sFc = 2.5;
    trZoomMove();
  }

  if (is_pressed(220, 280, 260, 319, px, py) && screen == 4 && trZoom == 1) { //MOVE TOTAL RECALL UP
    shY = shY + 190;
    trZoomMove();
  }

  if (is_pressed(0, 140, 40, 180, px, py) && screen == 4 && trZoom == 1) { //MOVE TOTAL RECALL LEFT
    shX = shX + 158;
    trZoomMove();
  }

  if (is_pressed(440, 140, 479, 180, px, py) && screen == 4 && trZoom == 1) { //MOVE TOTAL RECALL RIGHT
    shX = shX - 158;
    trZoomMove();
  }

  if (is_pressed(220, 0, 260, 40, px, py) && screen == 4 && trZoom == 1) { //MOVE TOTAL RECALL DOWN
    shY = shY - 190;
    trZoomMove();
  }

  if (is_pressed(0, 0, 39, 39, px, py) && trZoom == 1) { //EXIT TRZOOM BACK TO TOTAL RECALL FULL SCALE
    screen = 4;
    trZoom = 0;
    shX = 30;
    shY = 0;
    sFc = 1.333;
    switchScreen();
  }
}

void switchScreen() {  //---------------------------------------switchScreen-------------------------------------------------
  switch (screen) {
    case 1: //LIST SCREEN
      if (screenSaver == 1 | screenCommandKeyboard == 1 | screenKeypadFlag == 1) {
        my_lcd.Fill_Screen(BLACK);
        my_lcd.Set_Text_Size(2);
        my_lcd.Set_Text_colour(GREEN);
        my_lcd.Print_String(">", 460, 300);
        my_lcd.Set_Text_Size(1);
        screenHeader();
        screenList();
      }
      else {
        my_lcd.Set_Text_Size(2);
        my_lcd.Print_String("  ", 0, 300);
        my_lcd.Set_Text_Size(1);
        screenList();
        prevScreen = 1;
      }
      break;

    case 2: //TITLE SCREEN
      if (screenSaver == 1 | screenCommandKeyboard == 1 | screenKeypadFlag == 1) {
        my_lcd.Fill_Screen(BLACK);
        my_lcd.Set_Text_Size(2);
        my_lcd.Set_Text_colour(GREEN);
        my_lcd.Print_String("<", 0, 300);
        my_lcd.Print_String(">", 460, 300);
        my_lcd.Set_Text_Size(1);
        screenHeader();
        screenTitleListText();
        screenTrackList();
      }
      else {
        my_lcd.Set_Text_Size(2);
        my_lcd.Set_Text_colour(GREEN);
        my_lcd.Print_String("<", 0, 300);
        my_lcd.Print_String(">", 460, 300);
        my_lcd.Set_Text_Size(1);
        screenTitleList();
        screenTitleListText();
        prevScreen = 2;
      }

      break;

    case 3: //TRACK SCREEN
      if (screenSaver == 1 | screenCommandKeyboard == 1 | screenKeypadFlag == 1) {
        my_lcd.Fill_Screen(BLACK);
        my_lcd.Set_Text_Size(2);
        my_lcd.Set_Text_colour(GREEN);
        my_lcd.Print_String("<", 0, 300);
        my_lcd.Print_String(">", 460, 300);
        my_lcd.Set_Text_Size(1);
        screenHeader();
        screenTrackList();
      }
      else {

        my_lcd.Set_Text_Size(2);
        my_lcd.Set_Text_colour(GREEN);
        my_lcd.Print_String("<", 0, 300);
        my_lcd.Print_String(">", 460, 300);
        my_lcd.Set_Text_Size(1);
        if (prevScreen == 4) {
          my_lcd.Fill_Screen(BLACK);
          my_lcd.Set_Text_Size(2);
          my_lcd.Set_Text_colour(GREEN);
          my_lcd.Print_String("<", 0, 300);
          my_lcd.Print_String(">", 460, 300);
          my_lcd.Set_Text_Size(1);
          screenHeader();
        }

        screenTrackList();
        prevScreen = 3;
      }
      break;

    case 4: //TOTAL RECALL SCREEN
      screenTotalRecall();
      totalRecallUpdateInit();
      my_lcd.Set_Text_Size(2);
      my_lcd.Print_String("<", 0, 300);
      my_lcd.Set_Text_Size(1);
      prevScreen = 4;
      break;
  }
}

It's over 9000 characters long, so might have to break it up.

Or you could have attached it to a post

full program attached.

I really think it's to do with my use of the "buff", and the reassignment of the commandString[] array.

Happy to take any advice whatsoever.

Anthony.

sketch_SSL_Total_Recall_v1.1.ino (39.1 KB)

commandString[4] = buff; //Copy the buffer back in to commandString[4]

You can not do this !! commandString[] is an array of char*, now you copy the pointer to buff[] , and the pointer to commandString[4] is permanently lost.

void scrollCommandText() { //SCROLL UP TEXT
  for (int i = 0; i < 4; i++) {
    commandString[i] = commandString[i + 1]; //Shift up one line in the array
  }

You shouldn't actually be shifting the lines, you should have a pointer to the location of the first line and modify that.

Thanks Deva,

Would you have a suggestion on how to do this?
I’m really lost at this point, even after researching how it should work.

Regards,
Anthony.

OK I have it!!! Spent a little more time on researching how constant arrays and pointers work.

I redefined the array as a constant length [60] which should be sufficient to hold a complete length user command.

char commandString[5][60] = {"Hello", "Welcome to the program", "System ready", "Please enter first commands", "#"};

The concatenate section is now....

        strcat(commandString[4], commandWords[(i) + (j * 5)]);
        strcat(commandString[4], " ");
        my_lcd.Print_String(commandString[4], 72, 20);
        delay(200);

and the scroll void is now....

  for (int i = 0; i < 4; i++) {
    memcpy(commandString[i], 0, sizeof(commandString[i]));
    strcpy(commandString[i], commandString[i + 1]); //Shift up one line in the array
  }

  memcpy(commandString[4], 0, sizeof(commandString[4]));
  strcat(commandString[4], "#");

Thanks you all for the guidance.

Anthony.

I can't help feeling that you are making this more complicated than it needs to be

Suggestions :

make commandString an array of pointers

char * commandString[] = {"Hello", "Welcome to the program", "System ready", "Please enter first commands", "#"};

One less array dimension to worry about

Don't muck about concatenating the output into a single string, just print each element when you need to

Don't move the contents of the array around, instead use variables to select which entries to print and change those instead

An example

char * commandString[] = {"Hello", "Welcome to the program", "System ready", "Please enter first commands", "#"};
const byte TOTAL_LINES = sizeof(commandString) / sizeof(commandString[0]);

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  printMenu(0, 2);
  printMenu(2, 3);
}

void loop()
{
}

void printMenu(byte startLine, byte endLine)
{
  for (int line = startLine; line < endLine; line++)
  {
    Serial.println(commandString[line]);
  }
  Serial.println();
}

NOTE : the printMenu function needs to have checks added to ensure that its parameters are reasonable

Would you have a suggestion on how to do this?

I thought i did, and now Bob has given you an example of that.

make commandString an array of pointers

as it was, but you may as well add 'const' in front of the declaration so you don't do anything silly like concatenating it and storing it somewhere.

I redefined the array as a constant length [60] which should be sufficient to hold a complete length user command.

that is a tad wasteful, to declare 300 bytes for that.
Ok by now i think i am repeating myself.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.