Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Not compatible with other libraries #133

Open
dwilliss opened this issue Dec 15, 2024 · 3 comments
Open

[Bug]: Not compatible with other libraries #133

dwilliss opened this issue Dec 15, 2024 · 3 comments
Assignees
Labels
bug Something isn't working

Comments

@dwilliss
Copy link

What happened?

Fails to compile when trying to incorporate other libraries into the sketch.
I have a library that I'm using on other ESP32 units to communicate between modules using ESP-NOW.

This tries to initialize WiFi, but the wifi stack included in Bluepad seems to be incompatible with the ESP32 3.0.7 version. There are things missing.

Bluepad32 Version

latest from develop branch

Bluepad32 version custom

4.1.0

Bluepad32 Platform

Arduino IDE

Platform version

Arduino IDE 2.3.4

Controller

PS4 DualShock clone

Microcontroller

ESP32

Microcontroller board

ESP32-Dev Kit

OS

Windows

Relevant log output

c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp: In member function 'bool EspNowChildNode::begin()':
c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp:59:12: error: 'class WiFiClass' has no member named 'setChannel'; did you mean 'channel'?
       WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);
            ^~~~~~~~~~
            channel
c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp:61:21: error: 'class WiFiClass' has no member named 'STA'
       while (!(WiFi.STA.started() || WiFi.AP.started())) {
                     ^~~
c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp:61:43: error: 'class WiFiClass' has no member named 'AP'
       while (!(WiFi.STA.started() || WiFi.AP.started())) {
                                           ^~
c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp:84:12: error: 'class WiFiClass' has no member named 'setChannel'; did you mean 'channel'?
       WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);
            ^~~~~~~~~~
            channel
c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp:86:21: error: 'class WiFiClass' has no member named 'STA'
       while (!(WiFi.STA.started() || WiFi.AP.started())) {
                     ^~~
c:\Users\dwill\Documents\Arduino\libraries\EspNowChildNode\EspNowChildNode.cpp:86:43: error: 'class WiFiClass' has no member named 'AP'
       while (!(WiFi.STA.started() || WiFi.AP.started())) {

Relevant sketch

// SAVE THIS TO EspNowChildNode.h
#ifndef ESP_NOW_CHILD_NODE_H
#define ESP_NOW_CHILD_NODE_H

#define NODE_MAIN		0
#define NODE_SOUND_BOARD	1
#define NODE_ASTROPIXELS	2
#define NODE_DOME_INTERNALS	3
#define NODE_CONTROLLER_MENU	4

#ifndef MAX_CLIENTS
#define MAX_CLIENTS 10
#endif

#ifndef EEPROM_OFFSET
#define EEPROM_OFFSET 0
#endif

// Channel to be used by the ESP-NOW protocol
#ifndef ESPNOW_WIFI_CHANNEL
#define ESPNOW_WIFI_CHANNEL 1
#endif


typedef void (*EspNowNodeCallback)(const char* command);


typedef struct client_definition {
  bool isDefined;
  uint8_t macAddr[6];
} client_definition;


class EspNowChildNode {

  private:
    int _nodeNumber;
    EspNowNodeCallback _callback;
    client_definition _clients[MAX_CLIENTS];

  public:

    static EspNowChildNode* Instance;

    EspNowChildNode(int nodeNumber);

    void SetCallback(EspNowNodeCallback callback) {
      _callback = callback;
    }

  
    bool begin();

    void SendToClient(int id, const char* command);

    void SendPairingMessage();


  private:
    bool IsBroadcastAddress(const uint8_t * mac_addr);
    void DispatchCommand(const char* command);
    static void printMAC(const uint8_t * mac_addr);
    static void OnDataSent(const uint8_t *mac_addr, int status);

    static void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) { 
      Instance->OnDataRecvInternal(mac_addr, incomingData, len);
    }

    void OnDataRecvInternal(const uint8_t * mac_addr, const uint8_t *incomingData, int len);
    bool RecordClient(int id, const uint8_t *macAddr);
    bool addPeer(const uint8_t *peer_addr);
    void ReadPeers();

};
////////////////////////////////////////////////////////////////////////
// Save this to EspNowChildNode.cpp


#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <EEPROM.h>
#include <MacAddress.h>
#include <EspNowChildNode.h>


typedef struct paring_data {
  uint8_t msgType;
  uint8_t id;
  uint8_t macAddr[6];
} pairing_data;


typedef struct message_data {
  uint8_t msgType;
  uint8_t id;
  char message[248];
} message_data;

#define MESSAGETYPE_MESSAGE 0
#define MESSAGETYPE_PAIRING 1




 //   int _nodeNumber;
 //   EspNowNodeCallback _callback;
 //   
 //   client_definition _clients[MAX_CLIENTS];



    EspNowChildNode::EspNowChildNode(int nodeNumber) {
      Instance = this;
      _nodeNumber = nodeNumber;
      _callback = (EspNowNodeCallback)0;
      EEPROM.begin(6);
    }

   
    bool EspNowChildNode::begin() {
      Serial.print("WiFi Mode: ");
      Serial.println(_nodeNumber == NODE_MAIN ? "AP" : "Station");

      WiFi.mode(_nodeNumber ? WIFI_STA : WIFI_AP);


        // // Set the device as a Station and Soft Access Point simultaneously
        // WiFi.mode(WIFI_AP_STA);
        // WiFi.STA.begin();
        // WiFi.begin(ssid, password);
      WiFi.begin();

      Serial.print("Channel: ");
      Serial.println(ESPNOW_WIFI_CHANNEL);
      WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);

      while (!(WiFi.STA.started() || WiFi.AP.started())) {
        delay(100);
      }

      Serial.print("MAC Address: ");
      Serial.println(_nodeNumber == NODE_MAIN ? WiFi.softAPmacAddress() : WiFi.macAddress());

      // Set the device as a Station and Soft Access Point simultaneously
      WiFi.mode(WIFI_AP_STA);
      // Set device as a Wi-Fi Station
      // WiFi.begin(ssid, password);
      WiFi.begin();
      // while (WiFi.status() != WL_CONNECTED) {
      //   delay(1000);
      //   Serial.println("Setting as a Wi-Fi Station..");
      // }
      
      // Serial.print("WiFi Mode: ");
      // Serial.println(ESPNOW_WIFI_MODE == WIFI_AP ? "AP" : "Station");
      // WiFi.mode(ESPNOW_WIFI_MODE);

      Serial.print("Channel: ");
      Serial.println(ESPNOW_WIFI_CHANNEL);
      WiFi.setChannel(ESPNOW_WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);

      while (!(WiFi.STA.started() || WiFi.AP.started())) {
        delay(100);
      }

      Serial.print("MAC Address: ");
      Serial.println(_nodeNumber == NODE_MAIN ? WiFi.softAPmacAddress() : WiFi.macAddress());

      Serial.print("Server SOFT AP MAC Address:  ");
      Serial.println(WiFi.softAPmacAddress());

      Serial.print("Station IP Address: ");
      Serial.println(WiFi.localIP());
      Serial.print("Wi-Fi Channel: ");
      Serial.println(WiFi.channel());

      if (esp_now_init() != ESP_OK) {
          Serial.println("Error initializing ESP-NOW");
          return false;
        }
      esp_now_register_send_cb(esp_now_send_cb_t(OnDataSent));
      esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
      ReadPeers();
      for (int i = 0 ; i < 10 ; ++i) {
        if (!_clients[i].isDefined) continue;
        Serial.print("Peer[");
        Serial.print(i);
        Serial.print("] => ");
        printMAC(_clients[i].macAddr);
        Serial.println();
        addPeer(_clients[i].macAddr);
      }
    return true;
    }

    void EspNowChildNode::SendToClient(int id, const char* command) {
      if (id != -1 && !_clients[id].isDefined) return;
      message_data data;
      data.msgType = MESSAGETYPE_MESSAGE;
      data.id = id;
      strncpy(data.message, command, sizeof(data.message));
      data.message[sizeof(data.message) - 1] = 0;
      int len = strlen(data.message) + 2;
      if (id == -1) 
        esp_now_send((uint8_t*)0, (uint8_t *) &data, len);
      else
        esp_now_send(_clients[id].macAddr, (uint8_t *) &data, len);
    }

    void EspNowChildNode::SendPairingMessage() {
      uint8_t broadcast[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
      paring_data data;
      data.msgType = MESSAGETYPE_PAIRING;
      data.id = _nodeNumber;
      if (_nodeNumber == NODE_MAIN) // Server is in AP mode, so need softAPMacAddress
        WiFi.softAPmacAddress(data.macAddr);
      else 
        WiFi.macAddress(data.macAddr);
      esp_now_send(broadcast, (uint8_t *) &data, sizeof(data));
    }


    bool EspNowChildNode::IsBroadcastAddress(const uint8_t * mac_addr) {
      for (int i = 0 ; i < 6 ; ++i) {
        if (mac_addr[i] != 0xFF) return false;
      }
      return true;
    }

    void EspNowChildNode::DispatchCommand(const char* command) {
      Serial.println(command);
      if (_callback) (*_callback)(command);
    }

    void EspNowChildNode::printMAC(const uint8_t * mac_addr){
      char macStr[18];
      snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
              mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
      Serial.print(macStr);
    }

    void EspNowChildNode::OnDataSent(const uint8_t *mac_addr, /* esp_now_send_status_t */ int status) {
      Serial.print("Last Packet Send Status: ");
      Serial.print(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success to " : "Delivery Fail to ");
      printMAC(mac_addr);
      Serial.println();
    }

    void EspNowChildNode::OnDataRecvInternal(const uint8_t * mac_addr, const uint8_t *incomingData, int len) { 
      Serial.print(len);
      Serial.print(" bytes of new data received from ");
      printMAC(mac_addr);
      Serial.println();

      message_data* data;
      paring_data* pairingData;
      uint8_t type = incomingData[0];       // first message byte is the type of message 
      switch (type) {
        case MESSAGETYPE_MESSAGE : 
          data = (message_data*)incomingData;
          DispatchCommand(data->message);
          break;
      
        case MESSAGETYPE_PAIRING:     
          pairingData = (paring_data*)incomingData;

          Serial.print("Got pairing message from client ");
          Serial.print(pairingData->id);
          Serial.print(" at MAC address ");
          printMAC(pairingData->macAddr);
          Serial.println();

          uint8_t id = pairingData->id;
          if (id == _nodeNumber) return;
          uint8_t clientMacAddress[6];
          for (int i = 0 ; i < 6 ; ++i) clientMacAddress[i] = pairingData->macAddr[i];
          RecordClient(pairingData->id, pairingData->macAddr);
          addPeer(clientMacAddress);
          if (id > 0 || id == _nodeNumber) return;  // if request came from anybody other than server, do not send a response;

          // We're a client and just got a PAIRING broadcast from the master
          // record its address and open a channel;
          // Then respond with a pairing response of our own

          pairingData->id = _nodeNumber;       // 0 is server
          if (_nodeNumber == NODE_MAIN) // Server is in AP mode, so need softAPMacAddress
            WiFi.softAPmacAddress(pairingData->macAddr);
          else 
            WiFi.macAddress(pairingData->macAddr);
          Serial.println("Responding");
          esp_err_t result = esp_now_send(clientMacAddress, (uint8_t *) pairingData, sizeof(paring_data));
          Serial.println("Responded");
          break; 
      }
    }


    bool EspNowChildNode::RecordClient(int id, const uint8_t *macAddr) {
      if (id >= MAX_CLIENTS) return false;  
      bool changed = false;
      int addr = id * 6 + EEPROM_OFFSET;
      for (int i = 0 ; i < 6 ; ++i, ++addr) {
        uint8_t oldVal = EEPROM.read(addr);
        _clients[id].macAddr[i] = macAddr[i];
        if (macAddr[i] == oldVal) continue;
        changed = true;
        EEPROM.write(addr, macAddr[i]);
      }
      if (changed) EEPROM.commit();
      return changed;
    }

    bool EspNowChildNode::addPeer(const uint8_t *peer_addr) {      // add pairing
      esp_now_peer_info_t slave;
      memset(&slave, 0, sizeof(slave));
      const esp_now_peer_info_t *peer = &slave;
      memcpy(slave.peer_addr, peer_addr, 6);
      
      slave.channel = ESPNOW_WIFI_CHANNEL; // pick a channel
      slave.encrypt = 0; // no encryption
      // check if the peer exists
      bool exists = esp_now_is_peer_exist(slave.peer_addr);
      if (exists) {
        // Slave already paired.
        Serial.println("Already Paired");
        return true;
      }
      else {
        esp_err_t addStatus = esp_now_add_peer(peer);
        if (addStatus == ESP_OK) {
          // Pair success
          Serial.println("Pair success");
          return true;
        }
        else 
        {
          Serial.println("Pair failed");
          return false;
        }
      }
    } 

    void EspNowChildNode::ReadPeers() {
      int addr = EEPROM_OFFSET;
      for (int n = 0 ; n < MAX_CLIENTS ; ++n) {
        for (int i = 0 ; i < 6 ; ++i) {
          _clients[n].macAddr[i] = EEPROM.read(addr++);
        }
        _clients[n].isDefined = !IsBroadcastAddress(_clients[n].macAddr);
      }
    }

EspNowChildNode* EspNowChildNode::Instance;


/////////////////////////////////////////////////////////////
// Example main sketch boiled down to just what wants to use this library

#include <EEPROM.h>

#include <EspNowChildNode.h>

void OnCommandReceived(const char* command) {
  Serial.println(command);
}

EspNowChildNode node(NODE_SOUND_BOARD);

char _inputBuffer[100];
int _inputOffset;

void setup() {
  _inputOffset = 0;
  Serial.begin(115200);
  if (!EEPROM.begin(6)) Serial.println("Can't init EEPROM?");
  EEPROM.begin(60);

  node.SetCallback(OnCommandReceived);
  node.begin();
}
@dwilliss dwilliss added the bug Something isn't working label Dec 15, 2024
@ricardoquesada
Copy link
Owner

mmm... interesting.

If you try develop branch from https://github.com/ricardoquesada/esp-idf-arduino-bluepad32-template, does it work ?

It uses Arduino Core v3.1.0, and requires esp-idf 5.3.2.

@gomer-noah
Copy link

I encountered the same problem trying to use ESP-NOW in conjunction with Bluepad32. Below is a much simpler sketch that also gives an error ( 'class WiFiClass' has no member named 'STA') in case that makes it easier to reproduce.

Versions:
Arduino IDE 2.3.4
ESP32 3.1.0
Bluepad32 4.1.0

Board:
ESP32 Dev Module

#include <WiFi.h>
#include <esp_wifi.h>

void readMacAddress(){
  uint8_t baseMac[6];
  esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
  if (ret == ESP_OK) {
    Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
                  baseMac[0], baseMac[1], baseMac[2],
                  baseMac[3], baseMac[4], baseMac[5]);
  } else {
    Serial.println("Failed to read MAC address");
  }
}

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

  WiFi.mode(WIFI_STA);
  WiFi.STA.begin();

  Serial.print("[DEFAULT] ESP32 Board MAC Address: ");
  readMacAddress();
}
 
void loop(){

}

I just needed to grab the MAC address so my workaround was to use the regular ESP32 libraries temporarily. It seems most basic ESP-NOW functionality still works with Bluepad32 so I didn't have a need to go the ESP-IDF route.

@ricardoquesada
Copy link
Owner

hopefully it will get fixed once I released the new version for Arduino IDE.

In the meantime, you can try the "template" project which is already based on ESP-IDF v5.3 and Arduino Core 3.1

https://github.com/ricardoquesada/esp-idf-arduino-bluepad32-template

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants