Copying a MAC Address

I'm using ESP32's and ESP_Now to send commands to 2 receivers, but just one at a time. I tried the broadcast method but ran into other problems.

If I send one address it works. I'm now trying to move one or the other MAC Address by using a switch and coping the address into a holding array then sending the holding array. I used arrays before but that was to look up elements, not copy one to the other. I did look on the forum and other online resource, I tried this method and obviously it doesn't work or I wouldn't be asking.

Here's the code I'm using.

/* Started with sipPuffToyCar_Mod example
    added NRF24L01 communications
    with corrections from forum
    Rev 3 added steering state to receiver
    Rev 4 Added sip/puff delay on steering
    Rev 5 Changed to ESP_NOW
    Rev 6 Added crawler controlS
          Can switch, by commenting out, tug and crawler
    Rev 7 Added logic to switch Xmitter from tug to crawler
*/

// Include Libraries
#include <esp_now.h>
#include <WiFi.h>
#include <SafeString.h>

// MAC Address of receivers
uint8_t broadcastAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};   // Sending address
uint8_t broadcastAddress1[] = {0xFC, 0xE8, 0xC0, 0x7C, 0xA2, 0x40};  // Tug MAC address
uint8_t broadcastAddress2[] = {0x60, 0x55, 0xF9, 0xEB, 0xE0, 0x06};  // Crawler Feather S2 2 MAC address

cSF(drvText_SS, 24);
cSF(strText_SS, 24);

#define SENSOR_PIN 34

#define SelectIn 21
int Select = 0;

#define SIP_THRESHOLD 2000 //analog val, 450
#define PUFF_THRESHOLD 3000 //analog val

#define POLL_INTERVAL 10 //ms

#define SHORT_ACTION_MIN 100 //ms
#define SHORT_ACTION_MAX 750 //ms
#define ACTION_SPACE_MIN 50 //ms
#define ACTION_SPACE_MAX 750 //ms

uint32_t sipStartTime;
uint8_t sipStarted = 0;
uint32_t lastSipTime;
uint32_t lastSipDuration;

uint32_t puffStartTime;
uint8_t puffStarted = 0;
uint32_t lastPuffTime;
uint32_t lastPuffDuration;

uint8_t ThrottleOutValue = 0;
uint8_t ThrottleTrimValue = 0;
uint8_t SteeringOutValue = 135;
uint8_t SteeringTrimValue = 0;

uint32_t SteeringDelay = 0;
uint32_t previousMillis = 0;
uint32_t StartSteeringDelay = 50;
uint8_t SteeringPause = 0;
uint32_t SteeringPauseDelay = 500;
uint32_t SteeringPauseStart = 0;

enum DRIVE_STATE {FORWARD, REVERSE, IDLE}; // Enumeration, FORWARD - 1, REVERSE = 2, IDLE = 3
char *DRIVE_STATE_STRS[] = {"forward", "reverse", "idle"}; // ? Defines words so that when Drive state = 1 Serial monitor will display Forward, etc
uint8_t driveState = IDLE;

// Define a data structure
typedef struct struct_message {
  int steering;
  int drive;
} struct_message;
 
// Create a structured object
struct_message myData;

// Peer info
esp_now_peer_info_t peerInfo;
 
// Callback function called when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  //Serial.print("\r\nLast Packet Send Status:\t");
 // Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

//
void setDrive(uint8_t state) {
 // pinMode(FORWARD_PIN, OUTPUT);
 // pinMode(REVERSE_PIN, OUTPUT);

  if (driveState == state)
    return;

  if (state == FORWARD) {
    myData.drive = 1;
    
   // digitalWrite(FORWARD_PIN, HIGH);

    //Serial.print (" Forward Pause = ");
    //Serial.print (SteeringPause);
    //Serial.print (" Time =  ");
    //Serial.println (SteeringPauseStart);
  }
  else if (state == REVERSE) {
    myData.drive = 2;
    
    //digitalWrite (REVERSE_PIN, HIGH);

    //Serial.print (" Reverse Pause = ");
    //Serial.print (SteeringPause);
    //Serial.print (" Time =  ");
    //Serial.println (SteeringPauseStart);
  }
  else {
    myData.drive = 0;
    
   // digitalWrite (FORWARD_PIN, LOW);
   // digitalWrite (REVERSE_PIN, LOW);
  }
  driveState = state;
}

//
void toggleReverse() {
  if (driveState == REVERSE)
    return;

  else if (driveState == IDLE)
    setDrive(REVERSE);
  else
    setDrive(IDLE);
}


void toggleForward() {
  if (driveState == FORWARD)
    return;

  else if (driveState == IDLE)
    setDrive(FORWARD);
  else
    setDrive(IDLE);
}

enum STEERING_STATE {LEFT, RIGHT, CENTER};
char *STEERING_STATE_STRS[] = {"left", "right", "center"};
uint8_t steeringState = CENTER;

void setSteering(uint8_t state) {

  if (steeringState == state)
    return;

  if (state == LEFT) {
    myData.steering = 1;
    //  && (millis() - SteeringPauseStart) > SteeringPauseDelay
    // This line was added to the If condition statement above
  //  Serial.print (" Left Pause = ");
  //  Serial.print (SteeringPause);
  //  Serial.print ("Pause Time =  ");
  //  Serial.println (millis() - SteeringPauseStart);

   // digitalWrite(LEFT_PIN, HIGH);
  }
  else if (state == RIGHT) {
    myData.steering = 2;
    //  && (millis() - SteeringPauseStart) > SteeringPauseDelay
    // This line was added to the If condition statement above
  //  Serial.print (" Right Pause = ");
  //  Serial.print (SteeringPause);
  //  Serial.print (" Pause Time =  ");
  //  Serial.println (millis() - SteeringPauseStart);

   // digitalWrite(RIGHT_PIN, HIGH);
  }
  else {
    myData.steering = 0;
  //  digitalWrite(LEFT_PIN, LOW);
  //  digitalWrite(RIGHT_PIN, LOW);
    SteeringPauseStart = millis();
    SteeringPause = 0;

  //  Serial.print (" Idle Pause = ");
  //  Serial.print (SteeringPause);
  //  Serial.print (" Pause Time =  ");
  //  Serial.println (millis() - SteeringPauseStart);
  }
  steeringState = state;
} // end void setSteering(uint8_t state)


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

  pinMode(SelectIn, INPUT_PULLUP);
 
   // Set ESP32 as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
 
  // Initilize ESP-NOW
  if (esp_now_init() != ESP_OK) {
   // Serial.println("Error initializing ESP-NOW");
    return;
  }
  
   // Register the send callback
  esp_now_register_send_cb(OnDataSent);
  
 // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
   // Serial.println("Failed to add peer");
    return;
  }

} // End ot Setup Loop


void loop() {
  Select = digitalRead(SelectIn);

  if(Select == HIGH){
    byte i;
    for (i=0; i<(sizeof(broadcastAddress1)/sizeof(int)); i++)
      {
        broadcastAddress[i] = broadcastAddress1[i]; // Tug MAC address
        Serial.println("broadcastAddress1");
      }
   }
  else if(Select == LOW){
    byte i;
    for (i=0; i<(sizeof(broadcastAddress2)/sizeof(int)); i++)
      {
        broadcastAddress[i] = broadcastAddress2[i]; // Crawler Feather S2 2 MAC address
        Serial.println("broadcastAddress2");
      }
    }

  
  int16_t val = analogRead(SENSOR_PIN); // Read Pressure Switch < 450 = SIP, > 550 = Puff
  // Serial.println(val);
  
  if (!sipStarted && val < SIP_THRESHOLD) {
    SteeringPause = 1;
    sipStarted = 1;
    sipStartTime = millis(); //Store Sip Start Time
  }
  else if (sipStarted && val > SIP_THRESHOLD) {// SIP has Stopped
    sipStarted = 0;
    uint32_t duration = millis() - sipStartTime;

    if (duration > SHORT_ACTION_MIN) {
      uint32_t prevLastSipTime = lastSipTime;
      uint32_t prevLastSipDuration = lastSipDuration;

      lastSipTime = millis();
      lastSipDuration = duration;

      uint32_t space = sipStartTime - prevLastSipTime;

      //two shorts in a row
      if (prevLastSipDuration < SHORT_ACTION_MAX &&
          lastSipDuration < SHORT_ACTION_MAX &&
          space > ACTION_SPACE_MIN && space < ACTION_SPACE_MAX) {
        toggleReverse();
      }
    }
  }

  if (!puffStarted && val > PUFF_THRESHOLD) {
    SteeringPause = 1;
    puffStarted = 1;
    puffStartTime = millis();
  }
  else if (puffStarted && val < PUFF_THRESHOLD) {
    puffStarted = 0;
    uint32_t duration = millis() - puffStartTime;
    if (duration > SHORT_ACTION_MIN) {
      uint32_t prevLastPuffTime = lastPuffTime;
      uint32_t prevLastPuffDuration = lastPuffDuration;

      lastPuffTime = millis();
      lastPuffDuration = duration;

      uint32_t space = puffStartTime - prevLastPuffTime;

      //two shorts in a row
      if (prevLastPuffDuration < SHORT_ACTION_MAX &&
          lastPuffDuration < SHORT_ACTION_MAX &&
          space > ACTION_SPACE_MIN && space < ACTION_SPACE_MAX) {
        toggleForward();
      }
    }
  }

  //update steering
  if (sipStarted && (millis() > (sipStartTime + SteeringPauseDelay)))
    setSteering(LEFT);
  else if (puffStarted && (millis() > (puffStartTime + SteeringPauseDelay)))
    setSteering(RIGHT);
  else
    setSteering(CENTER);

  // Set Throttle Output with Trim

 // ThrottleTrimValue = map(analogRead(ThrottleTrimInput), 0, 1024, 85, 135) - 110;

  if (DRIVE_STATE_STRS[driveState] == "forward") {
   // ThrottleOutValue = (240 - ThrottleTrimValue) ;
    //analogWrite(ThrottleOutput, ThrottleOutValue);
    //  Serial.print("  Throttle Out = ");
    //   Serial.print(ThrottleOutValue);
  }
  else if (DRIVE_STATE_STRS[driveState] == "reverse") {
   // ThrottleOutValue = (30  - ThrottleTrimValue);
   // analogWrite(ThrottleOutput, ThrottleOutValue);
    //   Serial.print("  Throttle Out = ");
    //   Serial.print(ThrottleOutValue);
  }
  else {
   // ThrottleOutValue = (135  - ThrottleTrimValue);
    //analogWrite(ThrottleOutput, ThrottleOutValue);
    //    Serial.print("  Throttle Out = ");
    //     Serial.print(ThrottleOutValue);
  }
  // Set Steeering Output with Trim

 // SteeringTrimValue = map(analogRead(SteeringTrimInput), 0, 1024, 85, 135) - 110;

  // Delay for Steering change

  unsigned long currentmillis = millis();
  int CenterStop ;

  if (currentmillis - previousMillis > StartSteeringDelay) {
    previousMillis = currentmillis;
    CenterStop = (135 + SteeringTrimValue);

    if ((STEERING_STATE_STRS[steeringState] == "right") && (SteeringOutValue < 230)) {

    //  SteeringOutValue = ((SteeringOutValue + 10) );
     // analogWrite(SteeringOutput, SteeringOutValue);
    }

    if ((STEERING_STATE_STRS[steeringState] == "left") && (SteeringOutValue > 40)) {
     // SteeringOutValue = ((SteeringOutValue - 10)  );
      //analogWrite(SteeringOutput, SteeringOutValue);
    }

    if (STEERING_STATE_STRS[steeringState] == "center") {
      if (SteeringOutValue - CenterStop > 2) {
       // SteeringOutValue = ((SteeringOutValue) - 5);
      //  analogWrite(SteeringOutput, SteeringOutValue);
      }

      if (SteeringOutValue - CenterStop < -2) {
       // SteeringOutValue = ((SteeringOutValue) + 5);
       // analogWrite(SteeringOutput, SteeringOutValue);
      }
    } // End of CENTER if
  } // End of Main Steering If loop

 // Serial.print("  drive: ");
 // Serial.println(DRIVE_STATE_STRS[driveState]);
  //char text[20];
  //text[]= DRIVE_STATE_STRS[driveState];
  //radio.write(&text, sizeof(text));
  drvText_SS = DRIVE_STATE_STRS[driveState];
  //radio.write(drvText_SS.c_str(), drvText_SS.length() );

  //  Serial.print("  Throttle Out =" );
  //   Serial.print(ThrottleOutValue);
  //   Serial.print("  Throttle Trim =" );
  //   Serial.print(ThrottleTrimValue);

  //   Serial.print("   Steering Out ");
  //   Serial.print (SteeringOutValue);
  //   Serial.print("  Steering Trim =" );
  //  Serial.print(SteeringTrimValue);

  //   Serial.print(" CenterStop = " );
  //   Serial.println(CenterStop);
  //    Serial.print ("  Steering - Center =  ");
  //   Serial.print(SteeringOutValue - CenterStop);
  //     Serial.print("  Steering State =  ");
  //     Serial.print(myData.steering);
  //    Serial.print("\t");
  //     Serial.print("  Drive State =  ");
   //    Serial.println(myData.drive);
  strText_SS = STEERING_STATE_STRS[steeringState];
 // radio.write(strText_SS.c_str(), strText_SS.length() );

// Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
   
  if (result == ESP_OK) {
    //Serial.println("Sending confirmed");
  }
  else {
    //Serial.println("Sending error");
  }
  
    delay(POLL_INTERVAL);

  // if (sipStarted == 1){
  //    Serial.println ("Sip Started");
  //   StartSteeringDelay = 0;
  // }
  //    else if (puffStarted ==1){
  //    Serial.println ("Puff Started");
  //    }
  //   else {}
  //     }
}


I appreciate any help and comments
Thanks

Perhaps if, based on 'Select', you were to branch to a case where you implement one or the other address instead of copying one or the other into a holding array

That sounds like a better idea, I tried this.

if(Select == HIGH){
        uint8_t broadcastAddress[] = {0xFC, 0xE8, 0xC0, 0x7C, 0xA2, 0x40}; // Tug MAC address
        Serial.println("Tug");
   }
   
  else if(Select == LOW){
        uint8_t broadcastAddress[] = {0x60, 0x55, 0xF9, 0xEB, 0xE0, 0x06}; // Crawler Feather S2 2 MAC address
        Serial.println("Crawler");
     }

I defined broadcastAddress both as I had it with six elements of 0x00, and just as an array with six elements. It does compile and the serial monitor shows me the right one I've selected but it doesn't work to control the unit.

Thanks

Two concepts here: variable declaration and scope. You can't do this:

int x = 2;
int x = 2;

It attempts to re-declare an existing variable. But this is allowed:

int x = 2;
void foo() {
  int x = 3;
  Serial.println(x);
}

Each pair of curly braces creates a new block scope. Given two variables with the same name, the inner one is used, and the outer one is hidden or shadowed, and inaccessible. Therefore

void foo() {
  int x = 1;
  if (millis() % 2) {
    int x = 99;
  } else {
    int x = 100;
  }
  Serial.println(x);
}

will always print 1: no matter which way the millis() test goes, it is declaring a new instance of x, assigning it a value, and then immediately discarding it since the block is done. (In fact, the compiler might not generate any code for that, since it can see that the variable is not used at all.) It would be more useful to

void bar() {
  int x;  // also no point having initial value, will always be reassigned
  if (millis() % 2) {
    x = 99;
  } else {
    x = 100;
  }
  Serial.println(x);
}

Do you see how that applies to the code you posted?

More specifically for ESP-Now, you need to

  • register each peer before use, by copying the MAC into the peerInfo that gets passed
  • call the send function, pointing to a previously registered MAC

So you only need the two arrays with the actual values, and a pointer

uint8_t peer_tug[]     = {0xFC, 0xE8, 0xC0, 0x7C, 0xA2, 0x40};
uint8_t peer_crawler[] = {0x60, 0x55, 0xF9, 0xEB, 0xE0, 0x06};
uint8_t *which_peer = peer_tug; // pick one or the other

A function to do the registering to simplify that code

esp_err_t register_peer(const uint8_t *mac_addr) {
  esp_now_peer_info_t peerInfo = {};  // zero-initialize all fields like .channel and .encrypt
  memcpy(peerInfo.peer_addr, mac_addr, sizeof(peerInfo.peer_addr));
  return esp_now_add_peer(&peerInfo);
}

Used twice (btw, you were previously registering the all-zero broadcastAddress, which is pointless)

  if (register_peer(peer_tug) != ESP_OK) {
    // fail appropriately
  }
  if (register_peer(peer_crawler) != ESP_OK) {
    // fail appropriately
  }

Then to switch

  if (Select == HIGH) {
    which_peer = peer_tug;
  } else if (Select == LOW) {  // can Select be something other than HIGH or LOW?
    which_peer = peer_crawler;
  }

and send

  esp_err_t result = esp_now_send(which_peer, (uint8_t *) &myData, sizeof(myData));

Perfect! works exactly like I wanted it to. I had played with the broadcast mode recently so I had the code for registering each peer, I should have thought of that, although I still wouldn't have the switching logic.

Thanks for the detailed explanation and the help. I'll have to study this more and I'll save a copy for future reference.

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