Losing variable value when adding function to code

Hi there I have a problem with my code.

Quick overview,
I am prototyping with an Arduino Uno that is hooked up to a nRF8001 BLE and a Nokia 5110 screen. I have wirtten an app on my phone that sends a command to the BLE to the Arduino and then displays on the screen.
Below is the code that works and does what I just explained:

#include <SPI.h>
#include "Adafruit_BLE_UART.h"
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 2
#define ADAFRUITBLE_RST 9
Adafruit_BLE_UART uart = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);

Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16

// Logo Adafruit
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };


void setup(void)
{ 
  Serial.begin(9600);
  Serial.println(F("BLE has Begun"));
  uart.setRXcallback(rxCallback);
  uart.setACIcallback(aciCallback);
  uart.begin();
  display.begin();
  Serial.println(F("Display has begun"));
  display.setContrast(50);
  display.display();
  delay(3000);
  display.clearDisplay();
  display.display();
}
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;
void loop()
{ 
  uart.pollACI();  
}
void aciCallback(aci_evt_opcode_t event)
{
  switch(event)
  {
    case ACI_EVT_DEVICE_STARTED:
      Serial.println(F("Advertising started"));
      break;
    case ACI_EVT_CONNECTED:
      Serial.println(F("Connected!"));
      break;
    case ACI_EVT_DISCONNECTED:
      Serial.println(F("Disconnected or advertising timed out"));
      break;
    default:
      break;
  }
}
void rxCallback(uint8_t *buffer, uint8_t len)
{
  int i;
  String m;
  Serial.print(m);
  Serial.print(F("Received "));
  Serial.print(len);
  Serial.print(F(" bytes: "));
  for(i=0; i<len; i++){
   char n = buffer[i];
   m += String(n);
  }
  Serial.print("M's Value: \n");
  Serial.print(m);
  checkFunctions(m);
}
int checkFunctions(String m){
  Serial.print("\nNo more Chars, now checking Functions\n");
  Serial.print(m);
  if(m == "clear"){
    display.clearDisplay();
    display.display();
  }
  else if(m == "readytime"){
    Serial.print("\nSetting Time\n");
  }
  else if(m == "clock"){
    Serial.println(F("\nWe are going to draw a Clock"));
    display.display();
    delay(2000);
    display.clearDisplay();
  }
}

When I add either another “else if” statement or a completely new function I lose the “m” vairable’s value which is in the rxCallBack function. The “m” variable holds text it receives from my phone. Is this a bug?? Or is something wrong with my IDE? Or am I missing something? Below again is the same code with the added function and else if statment and when I run this code the “m” value is empty, it prints nothing.

#include <SPI.h>
#include "Adafruit_BLE_UART.h"
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 2
#define ADAFRUITBLE_RST 9
Adafruit_BLE_UART uart = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);Adafruit_BLE_UART BTLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);

Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16

// Logo Adafruit
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };


void setup(void)
{ 
  Serial.begin(9600);
  Serial.println(F("BLE has Begun"));
  uart.setRXcallback(rxCallback);
  uart.setACIcallback(aciCallback);
  uart.begin();
  display.begin();
  Serial.println(F("Display has begun"));
  display.setContrast(50);
  display.display();
  delay(3000);
  display.clearDisplay();
  display.display();
}
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;
void loop()
{ 
  uart.pollACI();  
}
void aciCallback(aci_evt_opcode_t event)
{
  switch(event)
  {
    case ACI_EVT_DEVICE_STARTED:
      Serial.println(F("Advertising started"));
      break;
    case ACI_EVT_CONNECTED:
      Serial.println(F("Connected!"));
      break;
    case ACI_EVT_DISCONNECTED:
      Serial.println(F("Disconnected or advertising timed out"));
      break;
    default:
      break;
  }
}
void rxCallback(uint8_t *buffer, uint8_t len)
{
  int i;
  String m;
  Serial.print(m);
  Serial.print(F("Received "));
  Serial.print(len);
  Serial.print(F(" bytes: "));
  for(i=0; i<len; i++){
   char n = buffer[i];
   m += String(n);
  }
  Serial.print("M's Value: \n");
  Serial.print(m);
  checkFunctions(m);
}
int checkFunctions(String m){
  Serial.print("\nNo more Chars, now checking Functions\n");
  Serial.print(m);
  if(m == "clear"){
    display.clearDisplay();
    display.display();
  }
  else if(m == "readytime"){
    Serial.print("\nSetting Time\n");
  }
  else if(m == "clock"){
    Serial.println(F("\nWe are going to draw a Clock"));
    display.display();
    delay(2000);
    display.clearDisplay();
  }
  else if (m == "clock"){
      drawClock();
  }
}

void drawClock(){
 display.setCursor(37,0);
 display.println("12");
 display.setCursor(40,41);
 display.println("6");
 display.setCursor(79,21);
 display.println("3");
 display.setCursor(0,21);
 display.println("9");
 display.fillCircle(display.width()/2, display.height()/2, 2, BLACK);
}

m has local scope in rxCallback

to access it in other functions, you must declare it globally instead.

void rxCallback(uint8_t *buffer, uint8_t len)
{
  int i;
  String m;
  Serial.print(m);

I see 2 variables called “m”.
This:

  String m;

inside the function void rxCallback(uint8_t *buffer, uint8_t len).

And this:

int checkFunctions(String m){

as a parameter of this function.

Which one you are talking about?

What you say is true, but I am passing "m" to the next function so it should be fine. Also when I go to print "m" just before calling the "checkFunctions" function "m" is still empty.

But just incase I tried declaring "m" as a global variable and ran that code but it yielded the same empty result =(

BulldogLowell:
m has local scope in rxCallback

to access it in other functions, you must declare it globally instead.

void rxCallback(uint8_t *buffer, uint8_t len)

{
  int i;
  String m;
  Serial.print(m);




http://arduino.cc/en/Reference/scope

GenericArtist:
What you say is true, but I am passing "m" to the next function so it should be fine.

if it should be fine, why isn't it, then?

see luisilva's extension to my comment

keep track of your variable scope

This:

int checkFunctions(String m){

As far as I understand just makes it so that this function can only accept String variables, it is not re-declaring the variable.

luisilva:
I see 2 variables called "m".
This:

  String m;

inside the function void rxCallback(uint8_t *buffer, uint8_t len).

And this:

int checkFunctions(String m){

as a parameter of this function.

Which one you are talking about?

GenericArtist:
As far as I understand just makes it so that this function can only accept String variables, it is not re-declaring the variable.

no, that is declaring the variable of the value passed to the function a string... a local variable in the function

you can also learn about the anatomy of a function here

I am not sure why. None the less though even before the end of this function:

void rxCallback(uint8_t *buffer, uint8_t len)
{
  int i;
  String m;
  Serial.print(m);
  Serial.print(F("Received "));
  Serial.print(len);
  Serial.print(F(" bytes: "));
  for(i=0; i<len; i++){
   char n = buffer[i];
   m += String(n);
  }
  Serial.print("M's Value: \n");
  Serial.print(m);
  checkFunctions(m);
}

The last Serial.print(m) prints nothing if the added else if statement is in the code… Why? Why is code from another funtion effecting this?

BulldogLowell:

GenericArtist:
What you say is true, but I am passing “m” to the next function so it should be fine.

if it should be fine, why isn’t it, then?

see luisilva’s extension to my comment

keep track of your variable scope

Oh ok interesting. So I need to change it to String p or something else so it does not overwrite "m"? If the variable "m" is not a global variable does this still matter?

I also realize I am should call it void not int, my bad.

BulldogLowell:

GenericArtist:
As far as I understand just makes it so that this function can only accept String variables, it is not re-declaring the variable.

no, that is declaring the variable of the value passed to the function a string... a local variable in the function

you can also learn about the anatomy of a function here

GenericArtist:
Oh ok interesting. So I need to change it to String p or something else so it does not overwrite “m”? If the variable “m” is not a global variable does this still matter?

while technically it won’t, it is not good practice. try not to use the same name in different scope and you will observe fewer problems.

void rxCallback(uint8_t *buffer, uint8_t len)
{
  int i;
  //String m;
  Serial.print(m);
  Serial.print(F("Received "));
  Serial.print(len);
  Serial.print(F(" bytes: "));
  for(i=0; i<len; i++){
   char n = buffer[i];
   m += String(n);
  }
  Serial.print("M's Value: \n");
  Serial.print(m);
  checkFunctions(m);
}

unless m is global, it shouldn’t even compile…

If you do this

void rxCallback(uint8_t *buffer, uint8_t len)
{
  int i;
  String m;// you have not assigned a value to m in this scope...
  Serial.print(m);
  Serial.print(F("Received "));
  Serial.print(len);
  Serial.print(F(" bytes: "));
  for(i=0; i<len; i++){
   char n = buffer[i];
   m += String(n);
  }
  Serial.print("M's Value: \n");
  Serial.print(m);
  checkFunctions(m);
}

Oh sorry man, in the original code I posted for this thread “String m;” was not commented out. In the last post I did that you pulled form I forgot to comment it back in. It was from me testing a “m” as a Global variable. Otherwise yes you are correct it would not have compiled.

Edit:
Also I will take that into practice, the whole not using same variable names even in different functions

BulldogLowell:

GenericArtist:
Oh ok interesting. So I need to change it to String p or something else so it does not overwrite “m”? If the variable “m” is not a global variable does this still matter?

while technically it won’t, it is not good practice. try not to use the same name in different scope and you will observe fewer problems.

void rxCallback(uint8_t *buffer, uint8_t len)

{
 int i;
 //String m;
 Serial.print(m);
 Serial.print(F("Received “));
 Serial.print(len);
 Serial.print(F(” bytes: "));
 for(i=0; i<len; i++){
  char n = buffer[i];
  m += String(n);
 }
 Serial.print(“M’s Value: \n”);
 Serial.print(m);
 checkFunctions(m);
}




unless m is global, it shouldn't even compile...

If you do this



void rxCallback(uint8_t *buffer, uint8_t len)
{
 int i;
 String m;// you have not assigned a value to m in this scope…
 Serial.print(m);
 Serial.print(F("Received “));
 Serial.print(len);
 Serial.print(F(” bytes: "));
 for(i=0; i<len; i++){
  char n = buffer[i];
  m += String(n);
 }
 Serial.print(“M’s Value: \n”);
 Serial.print(m);
 checkFunctions(m);
}

If m is intended to be a global variable, then you should not also use it as the name of one of the parameter arguments to your function.

It wouldn't matter if the function parameter was named 'm' or 'p', if its not a reference or pointer, you have a copy and therefore are not referring to the same object inside the function.

As the String is global, you can just access it without an extra parameter, however if the function was in a different CPP file you will need to 'pass' it.

By reference:

int checkFunctions(String &m){
  m += "Hi";
  return 1;
}

Or by passing in a pointer type.

int checkFunctions(String *m){
  m->concat( "Hi" );
  return 1;
}

Then any changes to the function variable, will be in reference to the global variable.

Call the first version exactly the same as you had it, the second simply needs the strings pointer.

String m;
checkFunctions( m ); //Reference
checkFunctions( &m ); //Pointer