assign variable a value whos name is passed as another variable

Hi,

I’m looking for a way to write a variable but the name of the variable is passed as another variable. Code is blwo. We’re only interested in the calibrate function really. I’m sending the command to the arduino “calibrate tank TANK_FULL 987”
I want it to write the variable TANK_FULL (was defined at the top of the code) with the value 987. Likewise sending calibrate tank TANK_EMPTY 49 should assign TANK_EMPTY the value 49. I’m just not sure how to tell arduino the variable name is a variable, is this even possible?

// Demo Code for SerialCommand Library
// Steven Cogswell
// May 2011

//#include <SoftwareSerial.h>

//SoftwareSerial mySerial(9, 10); // RX, TX

// temp & Humidity
#include <DHT22.h>
#define DHT22_PIN 12
// Setup a DHT22 instance
DHT22 myDHT22(DHT22_PIN);

// tank water level
int sensorValue = 0;
int constrainedValue = 0;
int tankLevel = 0;
#define TANK_SENSOR 0
#define TANK_EMPTY 0
#define TANK_FULL 1023


/*RelayBrd */
//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 4;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 3;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 2;
boolean thisState = LOW;


#include <SerialCommand.h>
#define arduinoLED 13   // Arduino LED on board

SerialCommand sCmd;     // The demo SerialCommand object

void setup() {
  pinMode(arduinoLED, OUTPUT);      // Configure the onboard LED for output
  digitalWrite(arduinoLED, LOW);    // default to LED off

  //mySerial.begin(9600);
  //mySerial.println("Ready");
  
  Serial.begin(115200);

  // Setup callbacks for SerialCommand commands
  sCmd.addCommand("ON",   LED_on);          // Turns LED on
  sCmd.addCommand("OFF",  LED_off);         // Turns LED off
  
    sCmd.addCommand("calibrate",  calibrate);         // Turns LED off    
  sCmd.addCommand("getenv",   getEnv);
  sCmd.addCommand("relaybrd",   relayBrd);
  sCmd.addCommand("gettanklevel",   getTankLevel);
  sCmd.addCommand("setlouver",   setLouver);
  sCmd.addCommand("HELLO", sayHello);        // Echos the string argument back
  sCmd.addCommand("P",     processCommand);  // Converts two arguments to integers and echos them back
  sCmd.setDefaultHandler(unrecognized);      // Handler for command that isn't matched  (says "What?")
  Serial.println("Ready");
}

void loop() {
  sCmd.readSerial();     // We don't do much, just process serial commands
  
 // if (mySerial.available())
 //   Serial.write(mySerial.read());
 // if (Serial.available())
 //   mySerial.write(Serial.read());
  
}



void calibrate(){
  
  char *calItem;  //Item were calibrating, eg tank
  char *calVar;  // Variable were setting
  char *calVal;  // value were setting calVar to
  calItem = sCmd.next();
  calVar = sCmd.next();
  calVal = sCmd.next();
  if(calVar == NULL && calVal == NULL){
    if (calItem != NULL) {
    //int num = atol(arg);
   
       if (strcmp("tank", calItem) == 0) {
         Serial.println("calibration tank");
          //do something when var equals 1
          //registerWrite(1, state);
         
       }else{ 
          // if nothing else matches, do the default
          Serial.print("ERR got:");Serial.print(calItem);Serial.println(":");
      }
    }else{
        Serial.println("ERR need calibration type");
    }  
  }else{ // set calibration values
       if (strcmp("tank", calItem) == 0) {
         
         calVar = calVal; // [b]<<<--------- that won't work[/b]
         Serial.print("calibrated tank ");Serial.print(calVar);Serial.print(": ");Serial.println(calVal);
          //do something when var equals 1
          //registerWrite(1, state);
         
       }
  
  }
 
}
void relayBrd(){
  
  char *arg;
  char *arg1;
  arg = sCmd.next();
  arg1 = sCmd.next();

  
  if (arg != NULL) {
    //int num = atol(arg);
    if (arg1 != NULL) {
       int state = atol(arg1);
       if (strcmp("fan", arg) == 0) {
          //do something when var equals 1
          registerWrite(1, state);
         
       }else if(strcmp("water", arg) == 0){
          //do something when var equals 2
          registerWrite(2, state);
        
      }else if(strcmp("mister", arg) == 0){
          //do something when var equals 2
          registerWrite(3, state);
        
      }else if(strcmp("heater", arg) == 0){
          //do something when var equals 2
          registerWrite(4, state);
         
      }else{ 
          // if nothing else matches, do the default
          Serial.print("ERR got:");Serial.print(arg);Serial.println(":");
      }
    }else{
        Serial.println("ERR Relay state missing 1/0");
    }  
   
  }else{
    Serial.println("ERR Relay argument missing fan/water/heater/mister");
  }
}

// This method sends bits to the shift register:

void registerWrite(int whichPin, int whichState) {
  
     Serial.print("Relay ");Serial.print(whichPin);Serial.print(" set to ");Serial.println(whichState);
// the bits you want to send
  byte bitsToSend = 0;

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(latchPin, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);

  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

    // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);

}

void getEnv(){
  Serial.println("26 degC");
   DHT22_ERROR_t errorCode;
 Serial.print("Requesting data...");
  errorCode = myDHT22.readData();
  switch(errorCode)
  {
    case DHT_ERROR_NONE:
      Serial.print("Got Data ");
      Serial.print(myDHT22.getTemperatureC());
      Serial.print("C ");
      Serial.print(myDHT22.getHumidity());
      Serial.println("%");
      break;
    default:
    Serial.print("ERR DHT22 ");
    Serial.println(errorCode);
  }
  
}




void getTankLevel(){
  Serial.println("78% water level");
  sensorValue = analogRead( TANK_SENSOR );
  constrainedValue = constrain( sensorValue, TANK_EMPTY, TANK_FULL );
  tankLevel = map( constrainedValue, TANK_EMPTY, TANK_FULL, 0, 100 );
    
}

void setLouver() {
  char *arg;

 
  arg = sCmd.next();
  if (arg != NULL) {
    if(strcmp("OPEN", arg) == 0){
         Serial.println("Louver OPEN");
    }else if(strcmp("CLOSE", arg) == 0){
          Serial.println("Louver CLOSED");
    }else{
    Serial.print(arg);Serial.println(" not known");
    }
  }else{
    Serial.println("Louver command missing OPEN/CLOSE");
  }
}  

void LED_on() {
  Serial.println("LED on");
  digitalWrite(arduinoLED, HIGH);
}

void LED_off() {
  Serial.println("LED off");
  digitalWrite(arduinoLED, LOW);
}

void sayHello() {
  char *arg;
  arg = sCmd.next();    // Get the next argument from the SerialCommand object buffer

  if (arg != NULL) {    // As long as it existed, take it
    if(strcmp("HELLO", arg) == 0){
        Serial.print("YES ");
    Serial.println(arg); 
    }else{
    
    Serial.print("NO ");
    Serial.println(arg);
    
    }
  }
  else {
    Serial.println("Hello Pi");
  }
}


void processCommand() {
  int aNumber;
  char *arg;

  Serial.println("We're in processCommand");
  arg = sCmd.next();
  if (arg != NULL) {
    aNumber = atoi(arg);    // Converts a char string to an integer
    Serial.print("First argument was: ");
    Serial.println(aNumber);
  }
  else {
    Serial.println("No arguments");
  }

  arg = sCmd.next();
  if (arg != NULL) {
    aNumber = atol(arg);
    Serial.print("Second argument was: ");
    Serial.println(aNumber);
  }
  else {
    Serial.println("No second argument");
  }
}

// This gets set as the default handler, and gets called when no other command matches.
void unrecognized(const char *command) {
  Serial.println("What?");
}

You can't directly convert the names of variables to actual variables as the names are not stored by the compiler.

However a small look-up table could achieve that.

Those aren't variables. They are defined constants. You can't change those in code.

Furthermore, once the code is compiled and loaded to the board, the variable names are gone and replaced with addresses. So you can't use the names for anything. What you can do is use the address via a pointer.

Delta_G: What you can do is use the address via a pointer.

Could you elaborate please? I've tried to create a reference to one of the defined constants but it won't compile:

#define TANK_FULL 1023
int TANK_FULL = &TANK_FULL;

error: expected unqualified-id before numeric constant

Forget about trying to use the TANK_FULL definition - it’s a preprocessor directive - it’s long gone by the time the arduino has the sketch.

Instead, declare an integer variable to hold your calibration value. I assume you want to keep it through power cycles- keep it in EEPROM. Load it from there at start up and allow your calibration routine to overwrite it; when you do, store the new number in EEPROM.

TANK_FULL is NOT a variable. It is a name that the preprocessor substitutes for, wherever it appears. When the compiler runs,

int TANK_FULL = &TANK_FULL;

is seen as

int 1023 = &1023;

which is nonsense.

Ok I understand so I have removed the define and made it an int variable.

I'm back to my original question now and still a little confused as to how to achieve this with or without a pointer.

Here is how I do things like this: http://ideone.com/hLk8cp

Yeah I did it in a similar way, this means if, else if, else for every calibration type. Which I was trying to avoid. I thought there was a possibility to do what the question title asks. Of course this isn't what was asked but achieves the desired outcome I guess. I am interested if what I asked is actually possible though.

void calibrate(){
  
  char *calItem;  //Item were calibrating, eg tank
  char *calVar;  // Variable were setting
  char *calVal;  // value were setting calVar to
  calItem = sCmd.next();
  calVar = sCmd.next();
  calVal = sCmd.next();
  if(calVar == NULL && calVal == NULL){
    if (calItem != NULL) {
    //int num = atol(arg);
   
       if (strcmp("tank", calItem) == 0) {
         Serial.println("calibration tank");
       }else{ 
          // if nothing else matches, do the default
          Serial.print("ERR got:");Serial.print(calItem);Serial.println(":");
      }
    }else{
        Serial.println("ERR need calibration item");
    }  
  }else{ // set calibration values
       if (strcmp("tank", calItem) == 0) {
         if(strcmp("TANK_FULL", calVar) == 0){
            TANK_FULL = atol(calVal);
         }else if(strcmp("TANK_EMPTY", calVar) == 0){
            TANK_FULL = atol(calVal);
         }
         
         Serial.print("calibrated tank ");Serial.print(calVar);Serial.print(": ");Serial.println(calVal);
          //do something when var equals 1
          //registerWrite(1, state);
         
       }
  
  }

}
  char *calItem;  //Item were calibrating, eg tank
  char *calVar;  // Variable were setting
  char *calVal;  // value were setting calVar to
  calItem = sCmd.next();
  calVar = sCmd.next();
  calVal = sCmd.next();

Why not combine the declaration and initialization in one line?

If you use STL, then you can do this sort of thing:

configuration ["TANK_FULL"] = atol (arg);

That would be using a "map" collection.

http://www.gammon.com.au/forum/?id=11119

Without doing that you can have an array, eg.

typedef struct
  {
  const char * name;
  long value;
  }  tConfiguration;
  
tConfiguration configuration [] = 
  {
  { "TANK_FULL", 42 },
  { "TANK_EMPTY", 21 },
  
  // more here
  
  };
  
void setup () { }
void loop () { }

Now when you get a string incoming, you do a simple scan of the array to find the matching name, and then get/set the corresponding value.

PaulS:   char *calItem;  //Item were calibrating, eg tank   char *calVar;  // Variable were setting   char *calVal;  // value were setting calVar to   calItem = sCmd.next();   calVar = sCmd.next();   calVal = sCmd.next();

Why not combine the declaration and initialization in one line?

No reason, it's just how I program. It's messy till it works then I optimise where I can like how you suggested. Thanks for pointing it out though.

[quote author=Nick Gammon link=topic=193570.msg1430306#msg1430306 date=1381877742] If you use STL, then you can do this sort of thing:

configuration ["TANK_FULL"] = atol (arg);

That would be using a "map" collection.

http://www.gammon.com.au/forum/?id=11119

Without doing that you can have an array, eg.

typedef struct
  {
  const char * name;
  long value;
  }  tConfiguration;
  
tConfiguration configuration [] = 
  {
  { "TANK_FULL", 42 },
  { "TANK_EMPTY", 21 },
  
  // more here
  
  };
  
void setup () { }
void loop () { }

Now when you get a string incoming, you do a simple scan of the array to find the matching name, and then get/set the corresponding value. [/quote]

Excellent, thank you. I'll probably go the array route for what I need rather than taking that STL port overhead you linked, although that's a handy reference to have! As always thanks all for your assistance, most appreciated.