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

Sending data from PC to my ESP32 via BLE #195

Open
akuttervrinsightde opened this issue Oct 17, 2023 · 14 comments
Open

Sending data from PC to my ESP32 via BLE #195

akuttervrinsightde opened this issue Oct 17, 2023 · 14 comments

Comments

@akuttervrinsightde
Copy link

Ladies and gentlemen,

this is my first time writing here. I created a simple gamepad to send a few buttons and three axis via BLE to the PC. Works like a charm. But is it possible to send infos from my Unity application to the ESP32? Like a float value, an int value or at least a bool? I would like to use it for example to trigger the vibration strenght or colorize an RGB LED. Or at least switch the vibration or the LED on and off with a bool.

I am not very experienced tbh, so looking forward to your help!

@LeeNX
Copy link

LeeNX commented Oct 18, 2023

Congratulations.

Similar question has been asked a few times in different ways.
#165
#99
#43

My own work in this area paused at https://github.com/LeeNX/ESP32-BLE-Gamepad/tree/test-led, which could be further basically tested with https://nondebug.github.io/webhid-explorer/ but using Chrome.

My research has me thinking there is no real standard way to do this from the OS. I was thinking getting a working tech demo and patch SDL to support this, but I have not had time to go further yet. Plus the branch is a little old.

Hope this helps and we all make some progress.

@akuttervrinsightde
Copy link
Author

Thank you @LeeNX very much appreciated.

Ok I understand the issue. I will dig a bit deeper into this, let's see what my simple developer mind can achieve :-D

@AlEnterni
Copy link

Hello,
I am reaching out to inquire about the feasibility of retrieving data from a characteristic created in a similar fashion to the following code snippet:

pCharacteristic_FFB = pService->createCharacteristic( NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE );

This characteristic is intended to be utilized within a function, and the goal is to write to this characteristic from Python or any other program using a BLE library.
I am not well-versed in Bluetooth and BLE, and I'm curious to know if this approach is viable. Any insights or guidance on how this can be achieved would be greatly appreciated.
Thank you for your time and assistance.

Best regards,

@LeeNX
Copy link

LeeNX commented Nov 22, 2023

I believe it should be possible, but I currently have not got a working example yet. I think the HID/report interface might be easier, like using the webhid-explorer using Chrome.

My PlayerLEDs branch might help, commit LeeNX@8096d8e has a start

I also think you need to add Characteristic to a Service, plus if you want to write into it, you would need a callBack, which is in my branch.

Let us know how you go with this.

@AlEnterni
Copy link

I'm encountering difficulties with Nimble, and I'm seeking assistance in resolving the issue. I've followed the examples provided by the library, but I'm still unable to write to characteristics that should be writable.

To provide a bit more context, I'm using nRF Connect on my mobile device for the connection. While I can successfully read data from the characteristics, writing to them seems to be problematic. I'm wondering if anyone else has faced a similar issue or if there are insights into what might be causing this inconvenience.

@LeeNX
Copy link

LeeNX commented Nov 25, 2023

@AlEnterni are you having issues with the NimBLE library or the ESP32-BLE-Gamepad library?

Currently ESP32-BLE-Gamepad library does not have write support.

If you have an example or PR to extending the ESP32-BLE-Gamepad that would be awesome.

@EmanresuEmanreztuneb
Copy link

I'll make it short:

If this is still active, im willing to support/donate with more then just a smile!

@lemmingDev
Copy link
Owner

Might be something usable here
https://github.com/afpineda/Nus-NimBLE-Serial

@LeeNX
Copy link

LeeNX commented Feb 26, 2024

Thanks @lemmingDev , I was looking at adding the option for NUS type service, but I could just not get it added as an option in the ESP32-BLE-Gamepad library. This is more a limitation of my C skills, than any other problem.

Thou the linked library looks to do way more than I was thinking of adding.

If only there was an easy way to add BLE services without them been all tied together.

@AlEnterni
Copy link

Hello everyone,

I've been working on modifying a BLE library for my project. My goal is to write a value to a characteristic and create a function to retrieve that value. However, due to my limited programming knowledge, I'm encountering an error that I can't seem to resolve. Here's the code snippet along with the error message:

---Blegamepad.h---



class BleGamepad
{
private:
    ...
    NimBLECharacteristic *pBeefCharacteristic;
    ...

public:
    ...
    void WriteData();
    ...
};

---Blegamepad.cpp---


...
void BleGamepad::taskServer(void *pvParameter)
    ...
    NimBLEService* pDeadService = pServer->createService("DEAD");
    NimBLECharacteristic* pBeefCharacteristic = pDeadService->createCharacteristic(
                                               "BEEF",
                                               NIMBLE_PROPERTY::READ |
                                               NIMBLE_PROPERTY::WRITE |
                                              );

    pBeefCharacteristic->setValue("Burger");

    ...

void BleGamepad::WriteData( )
{
    Serial.println((this->pBeefCharacteristic->getValue().c_str()));
}

When I try to run this code on my Arduino, I encounter the following error:


rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
Starting BLE work!

abort() was called at PC 0x400d4f3c on core 0

Backtrace: 0x40083949:0x3ffce0b0 0x40093515:0x3ffce0d0 0x40098a29:0x3ffce0f0 0x400d4f3c:0x3ffce170 0x400d31aa:0x3ffce1b0 0x400d2c62:0x3ffce1e0

ELF file SHA256: fab548ad5f8ea5c0

I would greatly appreciate any assistance or guidance on how to resolve this issue and successfully modify the code as intended. Thank you in advance for your help!

Best regards,

@LeeNX
Copy link

LeeNX commented Mar 19, 2024

I ran into similar issues, but my C skills are so little, maybe @lemmingDev could help make my branch work - https://github.com/LeeNX/ESP32-BLE-Gamepad/tree/leet-uart

The last three commits is where I tried to add NUS

@Talha-Babar
Copy link

Hi @LeeNX & @akuttervrinsightde ,

I am here for the same reason, i am developing the gamepad using esp32 with multiple buttons and axis. The gamepad is working fine and now i need a some variables from unreal engine for vibration and a value for actuators (motor) that will provide a jerk or elevation etc.

Is there something related to this you guys found and would you help me how can i achieve this.

Thanks and regards

@LeeNX
Copy link

LeeNX commented Aug 12, 2024

Sorry @Talha-Babar , not made any progress myself. Mostly because there is no standard way that I have found, that is not mimicking XBox controller (XInput) or Playstation interface, that is not really a standard - https://github.com/Mystfit/ESP32-BLE-CompositeHID/blob/master/examples/GamepadExamples/XboxXInputController/XboxXInputController.ino

But maybe ESP32-BLE-CompositeHID will do what you need and don't mind mimicking the XBox controller.

I was looking at the features of BLE, but been thinking about how would a device be shared between the Host OS and the Application and if it would be an all or nothing approach. ie: if you application opens the via HID, you would need full controller and process all of the HID, not just the feature set for like feedback.

Hope that helps.

@LeeNX
Copy link

LeeNX commented Nov 20, 2024

I was able to expose the NUS service in a test sketch last night, going to add to my gamepad repo and then drop the link here.

While testing, I was wonder if this is really going to be useful. The reason I say this, was I was looking for a way to debug and possible tweak my gamepad while running.

But in practice, I am thinking this might not really be possible, ie: gamepad connected to host OS, the host OS would also be able to open a NUS service to the gamepad and read debugging info and possible send commands or something. Capturing the streaming debugging messages to a file might have some use, if the host OS is a multi-tasking OS like Linux.

I think some people are hoping this might be a stepping stone to ForceFeedBack/Haptic interface, which could be used in custom setup, but I don't think it's a general function.

#include <Arduino.h>
#include <NimBLEDevice.h>
#include <BleGamepad.h>

//const int LED_PIN = LED_BUILTIN;
const int LED_PIN = 8;
unsigned long previousMillisLED = 0; // Stores the last time the LED was updated
unsigned long previousMillisTX = 0; // Stores the last time the LED was updated
const long intervalLED = 500;        // Interval at which to blink (in milliseconds)
const long intervalTX = 500;        // Interval at which to blink (in milliseconds)

bool ledState = LOW; // Stores the current state of the LED

// Initialize the BLE Gamepad object
BleGamepad bleGamepad("leet-Gamepad", "leenx", 100);

// BLE Serial setup
NimBLEServer *pServer = nullptr;
NimBLECharacteristic *pTxCharacteristic = nullptr;
std::string rxBuffer;

// UUIDs for the Serial Service
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

// Serial RX Callback
class MyCallbacks : public NimBLECharacteristicCallbacks {
  void onWrite(NimBLECharacteristic *pCharacteristic) {
    rxBuffer = pCharacteristic->getValue();
    if (!rxBuffer.empty()) {
      Serial.print("Received over BLE: ");
      Serial.println(rxBuffer.c_str());
      
      if (rxBuffer == "press") {
        bleGamepad.press(BUTTON_1); // Simulate button press
        Serial.println("Button 1 pressed");
      } else if (rxBuffer == "release") {
        bleGamepad.release(BUTTON_1); // Simulate button release
        Serial.println("Button 1 released");
      }
    } else {
      Serial.println("Received empty or invalid data.");
    }
  }
};

// Server connection callback
class MyServerCallbacks : public NimBLEServerCallbacks {
  void onConnect(NimBLEDevice* device) {
    Serial.println("Device connected, sending 'Connected' message!");
    
    // Send a 'Connected' message to the client
    std::string connectedMessage = "Connected to BLE Gamepad!";
    pTxCharacteristic->setValue(connectedMessage);  // Set the value of the TX characteristic
    pTxCharacteristic->notify();  // Notify the client that the TX value has changed
  }

  void onDisconnect(NimBLEDevice* device) {
    Serial.println("Device disconnected.");
  }
};

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_PIN, OUTPUT);

  // Initialize Serial communication at 115200 baud
  Serial.begin(115200);
  Serial.println("BLE Gamepad started. Waiting for connection...");

  // Initialize NimBLE stack
  NimBLEDevice::init("ESP32 Combo Device");

  // Create NimBLE Server
  pServer = NimBLEDevice::createServer();

  // Attach connection callbacks
  pServer->setCallbacks(new MyServerCallbacks());
  
  // Create BLE Serial Service
  NimBLEService *pService = pServer->createService(SERVICE_UUID);
  
  pTxCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID_TX,
      NIMBLE_PROPERTY::NOTIFY
  );
  
  // NimBLE adds 2902 Descriptors to Characteristic that had notify
  //pTxCharacteristic->addDescriptor(new NimBLE2902());
  
  NimBLECharacteristic *pRxCharacteristic = pService->createCharacteristic(
      CHARACTERISTIC_UUID_RX,
      NIMBLE_PROPERTY::WRITE
  );
  pRxCharacteristic->setCallbacks(new MyCallbacks());

  pService->start();

  // Start the BLE Gamepad
  bleGamepad.begin();

  // Start BLE advertising
  NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->start();

  Serial.println("BLE setup complete. Waiting for connection...");
}

// the loop function runs over and over again forever
void loop() {
  // Get the current time
  unsigned long currentMillis = millis();

  // Check if the interval has passed
  if (currentMillis - previousMillisLED >= intervalLED) {
    previousMillisLED = currentMillis; // Save the last time the LED was updated

    // Toggle the LED state
    ledState = !ledState;
    // Set the LED
    digitalWrite(LED_PIN, ledState);

    // Send feedback to the Serial Monitor
    Serial.print("LED is now ");
    Serial.print(ledState ? "ON" : "OFF");
    Serial.print(" | Current time: ");
    Serial.print(currentMillis);
    Serial.println(" ms");
  }

  if (bleGamepad.isConnected()) {
    Serial.println("Gamepad connected!");
    delay(100);
  } else {
    Serial.println("Gamepad not connected.");
    delay(100);
  }

  // Notify Serial Clients
  if (pTxCharacteristic) {
    if (currentMillis - previousMillisTX >= intervalTX) {
      previousMillisTX = currentMillis; // Save the last time the LED was updated

      // Send a message periodically if connected
      // Create a message with the current time in milliseconds
      std::string periodicMessage = "Sending periodic message at " + std::to_string(currentMillis) + " ms";
      pTxCharacteristic->setValue(periodicMessage);  // Set the value of the TX characteristic
      pTxCharacteristic->notify();  // Notify the client that the TX value has changed

    delay(100);    
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants