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

vendorRequestCallback not working in USBVendor.ino example #10670

Open
1 task done
ms4sman opened this issue Dec 2, 2024 · 4 comments
Open
1 task done

vendorRequestCallback not working in USBVendor.ino example #10670

ms4sman opened this issue Dec 2, 2024 · 4 comments
Assignees
Labels
Status: Needs investigation We need to do some research before taking next steps on this issue

Comments

@ms4sman
Copy link

ms4sman commented Dec 2, 2024

Board

ESP32-S3

Device Description

DevKitC

Hardware Configuration

Currently nothing else connected to any pins

Version

latest development Release Candidate (RC-X)

IDE Name

CLion with PlatformIO Plugin

Operating System

Windows and Linux

Flash frequency

40 MHz

PSRAM enabled

yes

Upload speed

115200

Description

I'm trying to use the example sketch USBVendor.ino from the examples folder. Everything works good, I can connect with the demo HTML page and communicate both ways and it's good. But the vendorRequestCallback method never seems to be hit. None of the Serial logs from it ever appear in the console.

Sketch

#ifndef ARDUINO_USB_MODE
#error This ESP32 SoC has no Native USB interface
#elif ARDUINO_USB_MODE == 1
#warning This sketch should be used when USB is in OTG mode
void setup() {}
void loop() {}
#else
#include "USB.h"
#include "USBVendor.h"

USBVendor Vendor;
const int buttonPin = 0;

//CDC Control Requests
#define REQUEST_SET_LINE_CODING        0x20
#define REQUEST_GET_LINE_CODING        0x21
#define REQUEST_SET_CONTROL_LINE_STATE 0x22

//CDC Line Coding Control Request Structure
typedef struct __attribute__((packed)) {
  uint32_t bit_rate;
  uint8_t stop_bits;  //0: 1 stop bit, 1: 1.5 stop bits, 2: 2 stop bits
  uint8_t parity;     //0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
  uint8_t data_bits;  //5, 6, 7, 8 or 16
} request_line_coding_t;

static request_line_coding_t vendor_line_coding = {9600, 0, 0, 8};

// Bit 0:  DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
static uint8_t vendor_line_state = 0;

//USB and Vendor events
static void usbEventCallback(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
  if (event_base == ARDUINO_USB_EVENTS) {
    arduino_usb_event_data_t *data = (arduino_usb_event_data_t *)event_data;
    switch (event_id) {
      case ARDUINO_USB_STARTED_EVENT: Serial.println("USB PLUGGED"); break;
      case ARDUINO_USB_STOPPED_EVENT: Serial.println("USB UNPLUGGED"); break;
      case ARDUINO_USB_SUSPEND_EVENT: Serial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en); break;
      case ARDUINO_USB_RESUME_EVENT:  Serial.println("USB RESUMED"); break;

      default: break;
    }
  } else if (event_base == ARDUINO_USB_VENDOR_EVENTS) {
    arduino_usb_vendor_event_data_t *data = (arduino_usb_vendor_event_data_t *)event_data;
    switch (event_id) {
      case ARDUINO_USB_VENDOR_DATA_EVENT:
        Serial.printf("Vendor RX: len:%u\n", data->data.len);
        for (uint16_t i = 0; i < data->data.len; i++) {
          Serial.write(Vendor.read());
        }
        Serial.println();
        break;

      default: break;
    }
  }
}

static const char *strRequestDirections[] = {"OUT", "IN"};
static const char *strRequestTypes[] = {"STANDARD", "CLASS", "VENDOR", "INVALID"};
static const char *strRequestRecipients[] = {"DEVICE", "INTERFACE", "ENDPOINT", "OTHER"};
static const char *strRequestStages[] = {"SETUP", "DATA", "ACK"};

//Handle USB requests to the vendor interface
bool vendorRequestCallback(uint8_t rhport, uint8_t requestStage, arduino_usb_control_request_t const *request) {
  Serial.printf(
    "Vendor Request: Stage: %5s, Direction: %3s, Type: %8s, Recipient: %9s, bRequest: 0x%02x, wValue: 0x%04x, wIndex: %u, wLength: %u\n",
    strRequestStages[requestStage], strRequestDirections[request->bmRequestDirection], strRequestTypes[request->bmRequestType],
    strRequestRecipients[request->bmRequestRecipient], request->bRequest, request->wValue, request->wIndex, request->wLength
  );

  bool result = false;

  if (request->bmRequestDirection == REQUEST_DIRECTION_OUT && request->bmRequestType == REQUEST_TYPE_STANDARD
      && request->bmRequestRecipient == REQUEST_RECIPIENT_INTERFACE && request->bRequest == 0x0b) {
    if (requestStage == REQUEST_STAGE_SETUP) {
      // response with status OK
      result = Vendor.sendResponse(rhport, request);
    } else {
      result = true;
    }
  } else
    //Implement CDC Control Requests
    if (request->bmRequestType == REQUEST_TYPE_CLASS && request->bmRequestRecipient == REQUEST_RECIPIENT_DEVICE) {
      switch (request->bRequest) {

        case REQUEST_SET_LINE_CODING:  //0x20
          // Accept only direction OUT with data size 7
          if (request->wLength != sizeof(request_line_coding_t) || request->bmRequestDirection != REQUEST_DIRECTION_OUT) {
            break;
          }
          if (requestStage == REQUEST_STAGE_SETUP) {
            //Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage)
            result = Vendor.sendResponse(rhport, request, (void *)&vendor_line_coding, sizeof(request_line_coding_t));
          } else if (requestStage == REQUEST_STAGE_ACK) {
            //In the ACK stage the response is complete
            Serial.printf(
              "Vendor Line Coding: bit_rate: %lu, data_bits: %u, stop_bits: %u, parity: %u\n", vendor_line_coding.bit_rate, vendor_line_coding.data_bits,
              vendor_line_coding.stop_bits, vendor_line_coding.parity
            );
          }
          result = true;
          break;

        case REQUEST_GET_LINE_CODING:  //0x21
          // Accept only direction IN with data size 7
          if (request->wLength != sizeof(request_line_coding_t) || request->bmRequestDirection != REQUEST_DIRECTION_IN) {
            break;
          }
          if (requestStage == REQUEST_STAGE_SETUP) {
            //Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage)
            result = Vendor.sendResponse(rhport, request, (void *)&vendor_line_coding, sizeof(request_line_coding_t));
          }
          result = true;
          break;

        case REQUEST_SET_CONTROL_LINE_STATE:  //0x22
          // Accept only direction OUT with data size 0
          if (request->wLength != 0 || request->bmRequestDirection != REQUEST_DIRECTION_OUT) {
            break;
          }
          if (requestStage == REQUEST_STAGE_SETUP) {
            //Send the response in setup stage
            vendor_line_state = request->wValue;
            result = Vendor.sendResponse(rhport, request);
          } else if (requestStage == REQUEST_STAGE_ACK) {
            //In the ACK stage the response is complete
            bool dtr = (vendor_line_state & 1) != 0;
            bool rts = (vendor_line_state & 2) != 0;
            Serial.printf("Vendor Line State: dtr: %u, rts: %u\n", dtr, rts);
          }
          result = true;
          break;

        default:
          // stall unknown request
          break;
      }
    }

  return result;
}

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.begin(115200);
  Serial.setDebugOutput(true);

  Vendor.onEvent(usbEventCallback);
  Vendor.onRequest(vendorRequestCallback);
  Vendor.begin();

  USB.onEvent(usbEventCallback);
  USB.webUSB(true);
  // Set the URL for your WebUSB landing page
  USB.webUSBURL("https://docs.espressif.com/projects/arduino-esp32/en/latest/_static/webusb.html");
  USB.begin();
}

void loop() {
  static int previousButtonState = HIGH;
  int buttonState = digitalRead(buttonPin);
  if (buttonState != previousButtonState) {
    previousButtonState = buttonState;
    if (buttonState == LOW) {
      Serial.println("Button Pressed");
      Vendor.println("Button Pressed");
      Vendor.flush();  //Without flushing the data will only be sent when the buffer is full (64 bytes)
    } else {
      Serial.println("Button Released");
      Vendor.println("Button Released");
      Vendor.flush();  //Without flushing the data will only be sent when the buffer is full (64 bytes)
    }
    delay(100);
  }

  while (Serial.available()) {
    size_t l = Serial.available();
    uint8_t b[l];
    l = Serial.read(b, l);
    Vendor.write(b, l);
    Vendor.flush();  //Without flushing the data will only be sent when the buffer is full (64 bytes)
  }
}
#endif /* ARDUINO_USB_MODE */

Debug Message

I am not getting output from the method mentioned above, that's the problem.

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@ms4sman ms4sman added the Status: Awaiting triage Issue is waiting for triage label Dec 2, 2024
@ms4sman
Copy link
Author

ms4sman commented Dec 5, 2024

I'm a bit confused. Is this meant to be an alternate code for me to try? If so, it doesn't even seem valid. the Vendor.begin method returns void as far as I can tell, both in 3.0.7 and 3.1.x. So that check thats assuming a bool isn't going to work...

@ms4sman
Copy link
Author

ms4sman commented Dec 5, 2024

That said, I took out that check so that it would build, and flashed it onto my ESP32 and tried it. Still nothing at all in the console it looks like when receiving messages from the browser or anything else that should be triggering them.

It looks like I may have misspoken in my first post on this topic. As far as I know, on Core 3.0.7 I have never been able to receive a message back from the browser or any other incoming message that should get logged with the vendor request or vendor event callbacks.

@ms4sman
Copy link
Author

ms4sman commented Dec 13, 2024

I have been continuing to mess with this while waiting for responses and I think I may just be even more confused than I was before. But here's some additional notes I have gathered so far.

I have been testing this using both the Arduino IDE and also PlatformIO with the same results. I have tried many different combinations of USB settings in Arduino IDE and build flags for PIO with varying results.

What I have narrowed down though is this:

  • On Core 2.0.17 the example worked well to connect to the browser and send messages from the browser to the ESP32. However, there was a problem with the flush command on the Vendor that meant calling flush didn't actually work and it would only send from ESP32 to browser when the buffer filled. You can't manually flush it.

  • On Core 2.0.17 the vendorRequestCallback code never seems to get hit ever that I can find. None of the Serial logs in there ever appear and I can find no evidence that any of that is being hit.

  • On Core 2.0.17 the ARDUINO_USB_EVENTS work good and get logged properly on plug and unplug.

  • On Core 3.0.7 the example works different. Now sending from the ESP32 to the browser works, and the flush issue is fixed. But messages sent from the browser to the ESP32 never seem to be arriving. There's no error in the browser, it seems to think it was sent just fine. But the ESP32 never logs it as it should in the code under ARDUINO_USB_VENDOR_EVENTS. This did work in 2.0.17 however.

  • On Core 3.0.7 the vendorRequestCallback stuff still does not work. Seems exactly the same as on 2.0.17. Never hit that I can find. I'd really like to use this though to determine when WebUSB actually connects.

  • On Core 3.0.7 the ARDUINO_USB_EVENTS still work just fine as far as I can tell.

Hopefully these additional notes are helpful. I'd really like to get this figured out! Let me know if I can provide any other useful info to help in debugging this!

@SuGlider SuGlider self-assigned this Jan 7, 2025
@SuGlider SuGlider added Status: Needs investigation We need to do some research before taking next steps on this issue and removed Status: Awaiting triage Issue is waiting for triage labels Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Needs investigation We need to do some research before taking next steps on this issue
Projects
None yet
Development

No branches or pull requests

3 participants
@ms4sman @SuGlider and others