Serial Keyboad Arrows to modify variables

To avoid re-flash your Arduino sketch every time you need to change a variable you can use the Keyboard Navigation keys/Cursor Control Keys to change some variables.

You can do this using the arrows in your keyboard and catching the codes read in the serial input.

Most of the keys use only 1 byte to identify its value/code, others keys use 3 or 4 bytes, for these case when they use more than 1 byte we only do a left shift and add the next byte, after that we compare it with known values of the Arrows in the keyboard.
When a key is valid do your task.


Cursor control keys


Navigation keys

Use this example code to do that, paste this in your main file, name it: ESP32_C3_KB_Commands_01.

#include <Arduino.h>


// This function must be located in the main file project to be able retunr its name.
inline const char* getProjectName(void)         // https://stackoverflow.com/a/8488201
{                                               // Se usa strrchr, porque en el ESP32 la constante __FILE__ entrega el nombre con la ruta del archivo.
    return strrchr(__FILE__, '\\') + 1;         // return the last ocurrency of char '\' plus 1, a partir de ahi esta el nombre del archivo.
}


void setup()
{
  Serial.begin(115200);
  delay( 3000 ); // power-up safety delay
}

void loop()
{
  // Other main tasks.
  Commands_main();
  delay(3);
}

// End of file.

And this in another file, name it "Serial_Commands.ino":

#define VOLUME_MAX      10
#define VOLUME_MIN      0
#define BIRGHT_MAX      32
#define BIRGHT_MIN      8


uint32_t  kb_cmd;
bool      mContinuous_Receiveing_flag;
uint8_t   mVolume = 5;
uint8_t   mBright = 16;

inline void Commands_main(void)
{
  if (Serial.available() > 0)
  {
    char inChar = Serial.read();

    if (mContinuous_Receiveing_flag)
    {
      kb_cmd <<= 8;
      kb_cmd  |= inChar;
    }
    else
    {
      kb_cmd   = 0;
      kb_cmd  |= inChar;
    }


    if ( mContinuous_Receiveing_flag && is_KB_Cmd(kb_cmd) )         // Only for complex commands
    {
      kb_cmd = 0;
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '0')
    {
      Serial.printf("\r\nProject name: [%s]\r\n", getProjectName() );
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '1')
    {
      Serial.printf("\r\nCommand: [%c]", inChar);             // print inChar as character.
      // code block
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '2')
    {
      Serial.printf("\r\nCommand: [%c]", inChar);             // print inChar as character.
      // code block
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '3')
    {
      Serial.printf("\r\nCommand: [%c]", inChar);             // print inChar as character.
      // code block
    }
    else
    {
      // Do nothing.
      Serial.print(".");                                          // No command indicator, or not implemented.
      // Serial.printf("\r\n Invalid command: {%X}", inChar);      // print inChar as hex number, uncomment to see the input value.
    }

    mContinuous_Receiveing_flag = true;
  }
  else
  {
    mContinuous_Receiveing_flag = false;
  }
}


bool is_KB_Cmd(uint32_t data)
{
  bool result;

  switch(data)
  {
    case 0x001B5B41:
      // code block
      mVolume = (mVolume < VOLUME_MAX)?++mVolume:VOLUME_MAX;
      Serial.printf("\r\nKB command: [%s], Volume: %d\r\n", "Up", mVolume);
      result = true;
      break;

    case 0x001B5B42:
      // code block
      mVolume = (mVolume > VOLUME_MIN)?--mVolume:VOLUME_MIN;
      Serial.printf("\r\nKB command: [%s], Volume: %d\r\n", "Down", mVolume);
      result = true;
      break;

    case 0x001B5B43:
      // code block
      mBright = (mBright < BIRGHT_MAX)?++mBright:BIRGHT_MAX;
      Serial.printf("\r\nKB command: [%s], Bright: %d\r\n", "Right", mBright);
      result = true;
      break;

    case 0x001B5B44:
      // code block
      mBright = (mBright > BIRGHT_MIN)?--mBright:BIRGHT_MIN;
      Serial.printf("\r\nKB command: [%s], Bright: %d\r\n", "Left", mBright);
      result = true;
      break;

    case 0x1B5B357E:      // Page Up
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "Page Up");
      result = true;
      break;

    case 0x1B5B367E:      // Page Down
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "Page Down");
      result = true;
      break;

    case 0x1B5B317E:      // Home
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "Home");
      result = true;
      break;

    case 0x1B5B347E:      // End
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "End");
      result = true;
      break;

    default:
      // code block
      result = false;
      break;
  }

  return result;
}


// End of file.


Changing a variable value in the terminal with the arrows keys.

That's it, use the arrows in your keyboard to see how a variable can be changed.
Regards
Jose Luis

1 Like

Neither compiles. Nice. MY MISTAKE... NEED BOTH COMPILED TOGETHER.

Sketch uses 257046 bytes (19%) of program storage space. Maximum is 1310720 bytes.
Global variables use 11668 bytes (3%) of dynamic memory, leaving 316012 bytes for local variables. Maximum is 327680 bytes.
first.ino
#include <Arduino.h>


// This function must be located in the main file project to be able retunr its name.
inline const char* getProjectName(void)         // https://stackoverflow.com/a/8488201
{                                               // Se usa strrchr, porque en el ESP32 la constante __FILE__ entrega el nombre con la ruta del archivo.
    return strrchr(__FILE__, '\\') + 1;         // return the last ocurrency of char '\' plus 1, a partir de ahi esta el nombre del archivo.
}


void setup()
{
  Serial.begin(115200);
  delay( 3000 ); // power-up safety delay
}

void loop()
{
  // Other main tasks.
  Commands_main();
  delay(3);
}

// End of file.
second.ino

#define VOLUME_MAX      10
#define VOLUME_MIN      0
#define BIRGHT_MAX      32
#define BIRGHT_MIN      8


uint32_t  kb_cmd;
bool      mContinuous_Receiveing_flag;
uint8_t   mVolume = 5;
uint8_t   mBright = 16;

inline void Commands_main(void)
{
  if (Serial.available() > 0)
  {
    char inChar = Serial.read();

    if (mContinuous_Receiveing_flag)
    {
      kb_cmd <<= 8;
      kb_cmd  |= inChar;
    }
    else
    {
      kb_cmd   = 0;
      kb_cmd  |= inChar;
    }


    if ( mContinuous_Receiveing_flag && is_KB_Cmd(kb_cmd) )         // Only for complex commands
    {
      kb_cmd = 0;
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '0')
    {
      Serial.printf("\r\nProject name: [%s]\r\n", getProjectName() );
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '1')
    {
      Serial.printf("\r\nCommand: [%c]", inChar);             // print inChar as character.
      // code block
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '2')
    {
      Serial.printf("\r\nCommand: [%c]", inChar);             // print inChar as character.
      // code block
    }
    else if (!mContinuous_Receiveing_flag && kb_cmd == '3')
    {
      Serial.printf("\r\nCommand: [%c]", inChar);             // print inChar as character.
      // code block
    }
    else
    {
      // Do nothing.
      Serial.print(".");                                          // No command indicator, or not implemented.
      // Serial.printf("\r\n Invalid command: {%X}", inChar);      // print inChar as hex number, uncomment to see the input value.
    }

    mContinuous_Receiveing_flag = true;
  }
  else
  {
    mContinuous_Receiveing_flag = false;
  }
}


bool is_KB_Cmd(uint32_t data)
{
  bool result;

  switch(data)
  {
    case 0x001B5B41:
      // code block
      mVolume = (mVolume < VOLUME_MAX)?++mVolume:VOLUME_MAX;
      Serial.printf("\r\nKB command: [%s], Volume: %d\r\n", "Up", mVolume);
      result = true;
      break;

    case 0x001B5B42:
      // code block
      mVolume = (mVolume > VOLUME_MIN)?--mVolume:VOLUME_MIN;
      Serial.printf("\r\nKB command: [%s], Volume: %d\r\n", "Down", mVolume);
      result = true;
      break;

    case 0x001B5B43:
      // code block
      mBright = (mBright < BIRGHT_MAX)?++mBright:BIRGHT_MAX;
      Serial.printf("\r\nKB command: [%s], Bright: %d\r\n", "Right", mBright);
      result = true;
      break;

    case 0x001B5B44:
      // code block
      mBright = (mBright > BIRGHT_MIN)?--mBright:BIRGHT_MIN;
      Serial.printf("\r\nKB command: [%s], Bright: %d\r\n", "Left", mBright);
      result = true;
      break;

    case 0x1B5B357E:      // Page Up
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "Page Up");
      result = true;
      break;

    case 0x1B5B367E:      // Page Down
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "Page Down");
      result = true;
      break;

    case 0x1B5B317E:      // Home
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "Home");
      result = true;
      break;

    case 0x1B5B347E:      // End
      // code block
      Serial.printf("\r\nKB command: [%s]\r\n", "End");
      result = true;
      break;

    default:
      // code block
      result = false;
      break;
  }

  return result;
}


// End of file.

Please post the error log of your compiler.

Note: The code was made for ESP32_C3.

first.ino

sketch_nov27a.ino:20:3: error: 'Commands_main' was not declared in this scope
   20 |   Commands_main();
      |   ^~~~~~~~~~~~~

exit status 1

Compilation error: 'Commands_main' was not declared in this scope

second.ino

sketch_nov27a.ino:36:51: error: 'getProjectName' was not declared in this scope
   36 |       Serial.printf("\r\nProject name: [%s]\r\n", getProjectName() );
      |                                                   ^~~~~~~~~~~~~~

exit status 1

Compilation error: 'getProjectName' was not declared in this scope

Should they be in the same folder? Probably... Yes... my mistake... need both together.

Sketch uses 257046 bytes (19%) of program storage space. Maximum is 1310720 bytes.
Global variables use 11668 bytes (3%) of dynamic memory, leaving 316012 bytes for local variables. Maximum is 327680 bytes.

Yes, both files must go in the same folder. :v:

IDE Screenshoot:

Should look like this.