PaulStoffregen / USBHost_t36

USB Host Library for Teensy 3.6 and 4.0
165 stars 85 forks source link

USBSerial fix add USBSerialEmu #44

Closed KurtE closed 3 years ago

KurtE commented 3 years ago

I was working on some other USBHost extensions and found I needed debug information that was being generated by a Teensy plugged into the USB host port that was output using Serial Emulation to be available. Likewise I wanted the ability to feed data back to that other Teensy.

So I decided to create USBHost_t36 implementation to handle the USB types that include Serial Emulation USBSerialEmu class.

The USBSerialEmu code was based on the USBSerial code as well as RAWHID. I found that there was a bug in the Receiving of data that was sent by the remote SEREMU output, I would miss the first character Fixed.

USBSerial fixed same bug in reading first character

@PaulStoffregen - This stuff was extracted from my MTP Device USB Host code, which is currently only in a test state.
I do have a simple sketch I ran, that echoes anything it receives from either Serial or Serial EMU on the board plugged into the host and echoes it on SerialUSB1.

// USBSerialEMU - Simple USBSerial or USBSerialEmu echo to SerialUSB1...
//
// This example is in the public domain

#include <USBHost_t36.h>

USBHost myusb;
USBHub hub1(myusb);
USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb);
USBSerial_BigBuffer userial(myusb, 1);  // USB Serial  big or little... 
USBSerialEmu seremu(myusb);

#if !defined(USB_TRIPLE_SERIAL) && !defined(USB_DUAL_SERIAL)
#error Program uses SerialUSB1 so needs Dual or Tripple Serial
#endif

USBDriver *drivers[] = {&hub1, &hid1, &hid2, &userial};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1", "HID1", "HID2", "USerial"};
bool driver_active[CNT_DEVICES] = {false, false};

// Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&seremu};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"seremu"};
bool hid_driver_active[CNT_DEVICES] = {false, false};

Stream *debug_stream = nullptr;

elapsedMillis emBlink = 0;

void setup()
{
  pinMode(13, OUTPUT);
  Serial.begin(2000000);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("\n\nUSB Serial Emulation Device Test Program");

  myusb.begin();
}

char buffer[512];

void loop()
{
  if (emBlink > 500) {
    emBlink = 0;
    digitalToggleFast(13);
  }
  myusb.Task();
  CheckHostDevicesChanged();
  processDebugStreams();
}

void CheckHostDevicesChanged()
{
  for (uint8_t i = 0; i < CNT_DEVICES; i++) {
    if (*drivers[i] != driver_active[i]) {
      if (driver_active[i]) {
        Serial.printf("*** Device % s - disconnected ***\n", driver_names[i]);
        driver_active[i] = false;
      } else {
        Serial.printf("*** Device % s % x: % x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
        driver_active[i] = true;

        const uint8_t *psz = drivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: % s\n", psz);
        psz = drivers[i]->product();
        if (psz && *psz) Serial.printf("  product: % s\n", psz);
        psz = drivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: % s\n", psz);
      }
    }
  }
  for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) {
    if (*hiddrivers[i] != hid_driver_active[i]) {
      if (hid_driver_active[i]) {
        Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]);
        hid_driver_active[i] = false;
      } else {
        Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
        hid_driver_active[i] = true;

        const uint8_t *psz = hiddrivers[i]->manufacturer();
        if (psz && *psz) Serial.printf("  manufacturer: %s\n", psz);
        psz = hiddrivers[i]->product();
        if (psz && *psz) Serial.printf("  product: %s\n", psz);
        psz = hiddrivers[i]->serialNumber();
        if (psz && *psz) Serial.printf("  Serial: %s\n", psz);
      }
    }
  }
}

void processDebugStreams() 
{
  //==============================================
  //  Debug stream stuff
  if (seremu) debug_stream = &seremu;
  else if (userial) debug_stream = &userial;
  else debug_stream = nullptr;

  uint16_t avail;
  uint16_t avail_for_write;
  if (debug_stream) {
    if ((avail = debug_stream->available())) {
      avail_for_write = SerialUSB1.availableForWrite();
      if (avail > avail_for_write) avail = avail_for_write;
      if (avail > sizeof(buffer)) avail = sizeof(buffer);
      debug_stream->readBytes(buffer, avail);
      SerialUSB1.write(buffer, avail);
    }

    if ((avail = SerialUSB1.available())) {
      avail_for_write = debug_stream->availableForWrite();
      if (avail > avail_for_write) avail = avail_for_write;
      if (avail > sizeof(buffer)) avail = sizeof(buffer);
      SerialUSB1.readBytes(buffer, avail);
      debug_stream->write(buffer, avail);
      Serial.printf("USB1->");
      Serial.write(buffer, avail);
    }
  }
}