Teensy 4.1 USB Host

I have the T4.1 and the PJRC USB Host cable attached.

My project connects to a Boss Katana guitar amp using this 'MS3' library: https://github.com/MrHaroldA/MS3 (well, with slightly modified Sysex codes as it's originally for a different amp than the Katana). Previously I had an Arduino Mega with a USB Host Sheild piggybacking it, and the MS3 library makes use of that by using this USB Host library: https://github.com/felis/USB_Host_Shield_2.0 I'm trying to still use the MS3 library but with the Teensy and the USB Host cable.

I have a few questions related to the T4.1 USB Host.

1) Is it possible to use the USB host port of the T4.1 (i.e with the cable), in conjunction with the 'USB_Host_Shield_2.0' from above? If so how would I achieve this?

If not, then...

2) Am I correct in saying that the only way to use the USB host port of the T4.1 with the cable, is to use this library: https://github.com/PaulStoffregen/USBHost_t36 ? If this is the case would anyone be able to help guide me with converting the MS3 library to use the USBHost_t36 instead of the USB_Host_Shield_2.0

3) When I run the HIDDeviceInfo example from the USBHost_t36 library and plug in a USB stick I get the following output:
Code:
USBDeviceInfo claim this=20005FC8

****************************************
** Device Level **
  vid=951
  pid=1697
  bDeviceClass = 0
  bDeviceSubClass = 0
  bDeviceProtocol = 0
09 04 00 00 02 08 06 50 00 07 05 81 02 00 02 00 07 05 02 02 00 02 00 

USBDeviceInfo claim this=20005FC8

****************************************
** Interface Level **
09 04 00 00 02 08 06 50 00 07 05 81 02 00 02 00 07 05 02 02 00 02 00

Does this mean the cable/port is functioning correctly? I'm so far in a limbo world where I'm struggling to work out if problems are hardware or software/library based as I don't quite know compatibility and what goes with what!
 
Sorry, this is probably not much help,

1) As far as I know of, no one has built in the Teensy native USB Host support into the USBHost shield library, directly or indirectly. But I could be wrong.

2) The USBHost_t36 is the current code base that was developed for the T3.6 and T4.x to support the USB Host capabilities. I am not sure if anyone else has developed an alternative. I try to help out as I can, but I do not know anything about your devices and how they work or connect up to USB. My quick guess is that it hooks up as a MIDI device? Which is part of the code I have not worked on.

3) The Hid device Info is not showing me much. That is other the pid and vid.... You might try to edit the usbhhost_t36.h file and turn on the debug (uncomment the line hear top of file) and rebuild and see if it gives any additional information.
You might try one of the MIDI exampls and see if it acts like it knows your device or not...

When I get a new device like this, I might try to do things like, plug it into a linux box, either RPI ro Ubuntu... And see if It shows me any information, like show verbose usbinfo on it, also look at system messages (dmesg) and see if that helps to deduce the data.

Good luck
 
Thanks KurtE!

You might try to edit the usbhhost_t36.h file and turn on the debug (uncomment the line hear top of file) and rebuild and see if it gives any additional information.

Here's the output with debugging from the HIDDeviceInfo example:
Code:
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 2000C000
periodictable = 2000C000
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 00 02 FF 00 FF 40 82 05 D8 01 00 00 01 02 00 01 
    VendorID = 0582, ProductID = 01D8, Version = 0000
    Class/Subclass/Protocol = 255 / 0 / 255
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: BOSS
enumeration:
Product: KATANA
enumeration:
Config data length = 188
enumeration:
Configuration Descriptor:
  09 02 BC 00 04 01 00 C0 00 
    NumInterfaces = 4
    ConfigurationValue = 1
  09 04 00 00 00 FF FF 00 00 
    Interface = 0
    Number of endpoints = 0
    Class/Subclass/Protocol = 255 / 255 / 0
  09 04 01 00 00 FF 02 02 00 
    Interface = 1
    Number of endpoints = 0
    Class/Subclass/Protocol = 255 / 2 / 2
  06 24 F1 01 00 00 
  09 04 01 01 01 FF 02 02 00 
    Interface = 1
    Number of endpoints = 1
    Class/Subclass/Protocol = 255 / 2 / 2
  07 24 01 01 00 01 00 
  0B 24 02 01 04 04 18 01 44 AC 00 
  06 24 F1 04 16 00 
  07 05 0D 05 70 00 01 
    Endpoint = 13 OUT
    Type = Isochronous
    Max Size = 112
    Polling Interval = 1
  07 25 01 00 00 00 00 
  09 04 02 00 00 FF 02 01 00 
    Interface = 2
    Number of endpoints = 0
    Class/Subclass/Protocol = 255 / 2 / 1
  09 04 02 01 01 FF 02 01 00 
    Interface = 2
    Number of endpoints = 1
    Class/Subclass/Protocol = 255 / 2 / 1
  07 24 01 07 00 01 00 
  0B 24 02 01 04 04 18 01 44 AC 00 
  06 24 F1 04 16 00 
  07 05 8E 25 70 00 01 
    Endpoint = 14 IN
    Type = Isochronous
    Max Size = 112
    Polling Interval = 1
  07 25 01 00 00 00 00 
  09 04 03 00 02 FF 03 00 00 
    Interface = 3
    Number of endpoints = 2
    Class/Subclass/Protocol = 255 / 3 / 0
  06 24 F1 02 03 03 
  07 05 03 02 00 02 01 
    Endpoint = 3 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 84 02 00 02 00 
    Endpoint = 4 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  09 04 03 01 02 FF 03 00 00 
    Interface = 3
    Number of endpoints = 2
    Class/Subclass/Protocol = 255 / 3 / 0
  07 05 03 03 00 02 04 
    Endpoint = 3 OUT
    Type = Interrupt
    Max Size = 512
    Polling Interval = 4
  07 05 85 03 00 02 04 
    Endpoint = 5 IN
    Type = Interrupt
    Max Size = 512
    Polling Interval = 4
enumeration:
USBHub memory usage = 960
USBHub claim_device this=200075A0
USBHub memory usage = 960
USBHub claim_device this=20007960

USBDeviceInfo claim this=20006EC8

****************************************
** Device Level **
  vid=582
  pid=1D8
  bDeviceClass = 255
  bDeviceSubClass = 0
  bDeviceProtocol = 255
09 04 00 00 00 FF FF 00 00 09 04 01 00 00 FF 02 02 00 06 24 F1 01 00 00 09 04 01 01 01 FF 02 02
00 07 24 01 01 00 01 00 0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16 00 07 05 0D 05 70 00 01
07 25 01 00 00 00 00 09 04 02 00 00 FF 02 01 00 09 04 02 01 01 FF 02 01 00 07 24 01 07 00 01 00
0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16 00 07 05 8E 25 70 00 01 07 25 01 00 00 00 00 09
04 03 00 02 FF 03 00 00 06 24 F1 02 03 03 07 05 03 02 00 02 01 07 05 84 02 00 02 00 09 04 03 01
02 FF 03 00 00 07 05 03 03 00 02 04 07 05 85 03 00 02 04 
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 00 00 00 FF FF 00 00 09 04 01 00 00 FF 02 02 00 06 24 F1 01 00 00 09 04 01 01 01 FF 02 02
00 07 24 01 01 00 01 00 0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16 00 07 05 0D 05 70 00 01
07 25 01 00 00 00 00 09 04 02 00 00 FF 02 01 00 09 04 02 01 01 FF 02 01 00 07 24 01 07 00 01 00
0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16 00 07 05 8E 25 70 00 01 07 25 01 00 00 00 00 09
04 03 00 02 FF 03 00 00 06 24 F1 02 03 03 07 05 03 02 00 02 01 07 05 84 02 00 02 00 09 04 03 01
02 FF 03 00 00 07 05 03 03 00 02 04 07 05 85 03 00 02 04 
 bInterfaceNumber = 0
 number end points = 0
 bInterfaceClass =    255
 bInterfaceSubClass = 255
 bInterfaceProtocol = 0
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 01 00 00 FF 02 02 00 06 24 F1 01 00 00 09 04 01 01 01 FF 02 02 00 07 24 01 01 00 01 00 0B
24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16 00 07 05 0D 05 70 00 01 07 25 01 00 00 00 00 09 04
02 00 00 FF 02 01 00 09 04 02 01 01 FF 02 01 00 07 24 01 07 00 01 00 0B 24 02 01 04 04 18 01 44
AC 00 06 24 F1 04 16 00 07 05 8E 25 70 00 01 07 25 01 00 00 00 00 09 04 03 00 02 FF 03 00 00 06
24 F1 02 03 03 07 05 03 02 00 02 01 07 05 84 02 00 02 00 09 04 03 01 02 FF 03 00 00 07 05 03 03
00 02 04 07 05 85 03 00 02 04 
 bInterfaceNumber = 1
 number end points = 0
 bInterfaceClass =    255
 bInterfaceSubClass = 2
 bInterfaceProtocol = 2
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 36 =  ???
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 01 01 01 FF 02 02 00 07 24 01 01 00 01 00 0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16
00 07 05 0D 05 70 00 01 07 25 01 00 00 00 00 09 04 02 00 00 FF 02 01 00 09 04 02 01 01 FF 02 01
00 07 24 01 07 00 01 00 0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16 00 07 05 8E 25 70 00 01
07 25 01 00 00 00 00 09 04 03 00 02 FF 03 00 00 06 24 F1 02 03 03 07 05 03 02 00 02 01 07 05 84
02 00 02 00 09 04 03 01 02 FF 03 00 00 07 05 03 03 00 02 04 07 05 85 03 00 02 04 
 bInterfaceNumber = 1
 number end points = 1
 bInterfaceClass =    255
 bInterfaceSubClass = 2
 bInterfaceProtocol = 2
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 37 =  ???
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 02 00 00 FF 02 01 00 09 04 02 01 01 FF 02 01 00 07 24 01 07 00 01 00 0B 24 02 01 04 04 18
01 44 AC 00 06 24 F1 04 16 00 07 05 8E 25 70 00 01 07 25 01 00 00 00 00 09 04 03 00 02 FF 03 00
00 06 24 F1 02 03 03 07 05 03 02 00 02 01 07 05 84 02 00 02 00 09 04 03 01 02 FF 03 00 00 07 05
03 03 00 02 04 07 05 85 03 00 02 04 
 bInterfaceNumber = 2
 number end points = 0
 bInterfaceClass =    255
 bInterfaceSubClass = 2
 bInterfaceProtocol = 1
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 02 01 01 FF 02 01 00 07 24 01 07 00 01 00 0B 24 02 01 04 04 18 01 44 AC 00 06 24 F1 04 16
00 07 05 8E 25 70 00 01 07 25 01 00 00 00 00 09 04 03 00 02 FF 03 00 00 06 24 F1 02 03 03 07 05
03 02 00 02 01 07 05 84 02 00 02 00 09 04 03 01 02 FF 03 00 00 07 05 03 03 00 02 04 07 05 85 03
00 02 04 
 bInterfaceNumber = 2
 number end points = 1
 bInterfaceClass =    255
 bInterfaceSubClass = 2
 bInterfaceProtocol = 1
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 37 =  ???
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 03 00 02 FF 03 00 00 06 24 F1 02 03 03 07 05 03 02 00 02 01 07 05 84 02 00 02 00 09 04 03
01 02 FF 03 00 00 07 05 03 03 00 02 04 07 05 85 03 00 02 04 
 bInterfaceNumber = 3
 number end points = 2
 bInterfaceClass =    255
 bInterfaceSubClass = 3
 bInterfaceProtocol = 0
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Descriptor 4 = INTERFACE

USBDeviceInfo claim this=20006EC8

****************************************
** Interface Level **
09 04 03 01 02 FF 03 00 00 07 05 03 03 00 02 04 07 05 85 03 00 02 04 
HIDParser claim this=20006140
HIDParser claim this=20006800
HIDParser claim this=2000AF80
HIDParser claim this=200049C0
HIDParser claim this=20006EE0
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT

It correctly identified the product (The Boss Katana guitar amp) although I won't pretend to know what 98% of the information given means :D BUT... It suggests to my limited knowledge that if nothing else the T4.1 built-in USB host port and cable are working.




So maybe option 2 is best.

Here's the MS3.h file:
Code:
/**
 * This is a simple library to control the Boss MS-3.
 *
 * Check README.md or visit https://github.com/MrHaroldA/MS3 for more information.
 *
 * Debug information:
 * - Define MS3_DEBUG_MODE in your sketch before including this library.
 *
 * Dependencies
 * - An Arduino with a USB Host Shield
 * - https://github.com/felis/USB_Host_Shield_2.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MS3_h
#define MS3_h

#include "Arduino.h"

/**
 * Overridable config.
 *
 * MS3_WRITE_INTERVAL_MSEC: The delay before a new message is sent after a write action.
 * MS3_READ_INTERVAL_MSEC: The delay before a new message is sent after a read action.
 * MS3_RECEIVE_INTERVAL_MSEC: The delay after receiving data from the MS-3.
 * MS3_HEADER: The manufacturer and device id header. Define MS3_CUSTOM_HEADER to override this.
 * MS3_QUEUE_SIZE: The maximum number of items in the send queue.
 */
#ifndef MS3_WRITE_INTERVAL_MSEC
#define MS3_WRITE_INTERVAL_MSEC 4
#endif

#ifndef MS3_READ_INTERVAL_MSEC
#define MS3_READ_INTERVAL_MSEC 25
#endif

#ifndef MS3_RECEIVE_INTERVAL_MSEC
#define MS3_RECEIVE_INTERVAL_MSEC  4
#endif

#ifndef MS3_CUSTOM_HEADER
const byte MS3_HEADER[6] = {0x41, 0x00, 0x00, 0x00, 0x00, 0x3B};
#endif

#ifndef MS3_CUSTOM_HANDSHAKE
const byte HANDSHAKE[15] = {0xF0, 0x7E, 0x00, 0x06, 0x02, 0x41, 0x3B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7};
#endif

#ifndef MS3_QUEUE_SIZE
#define MS3_QUEUE_SIZE 20
#endif

/**
 * The configuration options below are internal and should not be changed.
 */
#ifdef MS3_DEBUG_MODE
    #define MS3_DEBUG(x) Serial.print(x)
    #define MS3_DEBUGLN(x) Serial.println(x)
    #define MS3_DEBUG_AS(x, y) Serial.print(x, y)
#else
    #define MS3_DEBUG(x) (void)(x)
    #define MS3_DEBUGLN(x) (void)(x)
    #define MS3_DEBUG_AS(x, y) (void)(x)
#endif

#include "usbh_midi.h"
#include "Queue.h"

// General configuration.
const unsigned int INIT_DELAY_MSEC = 100;
const byte MS3_WRITE = 0x12;
const byte MS3_READ = 0x11;

// Return values.
const int8_t MS3_NOT_READY = 0;
const int8_t MS3_READY = 1;
const int8_t MS3_DATA_SENT = 2;
const int8_t MS3_DATA_RECEIVED = 3;
const int8_t MS3_NOTHING_HAPPENED = 4;
const int8_t MS3_ALMOST_IDLE = 5;
const int8_t MS3_IDLE = 6;

// Fixed data.
const byte SYSEX_START = 0xF0;
const byte SYSEX_END = 0xF7;
const unsigned long P_EDIT = 0x7F000001;

// Load the Queue class.
Queue Queue;

class MS3 : public USBH_MIDI {
    private:
        USB Usb;
        byte lastState = 0;
        bool ready = false;
        unsigned long nextMessage = 0;

        /**
         * The last bit of the data sent to the MS-3 contains a checksum of the parameter and data.
         */
        byte checksum(byte const *data, byte dataLength) {
            byte sum = 0, i;

            for (i = 8; i < 12 + dataLength; i++) {
                sum = (sum + data[i]) & (byte) 0x7F;
            }

            return ((byte) 128 - sum) & (byte) 0x7F;
        }

        /**
         * Construct and send a full SysEx message.
         */
        void send(const unsigned long address, byte *data, byte dataLength, byte action) {
            byte sysex[14 + dataLength] = {0};

            memcpy(sysex + 1, MS3_HEADER, 7);
            sysex[8] = (byte) (address >> 24);
            sysex[9] = (byte) (address >> 16);
            sysex[10] = (byte) (address >> 8);
            sysex[11] = (byte) (address);
            memcpy(sysex + 12, data, dataLength);

            sysex[0] = SYSEX_START;
            sysex[7] = action;
            sysex[12 + dataLength] = checksum(sysex, dataLength);
            sysex[13 + dataLength] = SYSEX_END;

            MS3::send(sysex);
        }

        /**
         * Send the data to the MS-3.
         */
        void send(byte *data) {
            byte result, dataLength = (byte) MS3::countSysExDataSize(data);

            MS3_DEBUG(F("TX:"));
            MS3::printSysEx(data, dataLength);
            if ((result = MS3::SendSysEx(data, dataLength)) != 0) {
                MS3_DEBUG(F(" *** Transfer error: "));
                MS3_DEBUG(result);
            }
            MS3_DEBUGLN(F("."));
        }

        /**
         * MS3_DEBUG printer for the received SysEx data.
         */
        void printSysEx(byte *data, byte dataLength) {
            char buf[10];

            for (byte i = 0; i < dataLength; i++) {
                sprintf(buf, " %02X", data[i]);
                MS3_DEBUG(buf);
            }
            MS3_DEBUG(F(" ("));
            MS3_DEBUG(dataLength);
            MS3_DEBUG(F(")"));
        }

        /**
         * Check if we've received any data.
         */
        bool receive(unsigned long &parameter, int &dataOut) {
            byte
                incoming[MIDI_EVENT_PACKET_SIZE] = {0},
                data[MIDI_EVENT_PACKET_SIZE] = {0},
                dataLength = 0,
                i;

            uint16_t rcvd;

            if (MS3::RecvData(&rcvd, incoming) == 0) {
                if (rcvd == 0) {
                    return false;
                }

                byte *p = incoming;
                for (i = 0; i < MIDI_EVENT_PACKET_SIZE; i += 4) {
                    if (*p == 0 && *(p + 1) == 0) {
                        break;
                    }

                    byte chunk[3] = {0};
                    if (MS3::extractSysExData(p, chunk) != 0) {
                        for (byte part : chunk) {
                            data[dataLength] = part;
                            dataLength++;

                            if (part == SYSEX_END) {
                                break;
                            }
                        }
                        p += 4;
                    }
                }
                MS3_DEBUG(F("RX:"));
                MS3::printSysEx(data, dataLength);
                MS3_DEBUGLN(F("."));

                // Return values.
                parameter = 0;
                for (i = 0; i < 4; i++) {
                    parameter += (unsigned long) data[8 + i] << (3 - i) * 8;
                }
                dataOut = (byte) data[dataLength - 3];

                // If the data is one byte longer, add x times 128 to the return value for a full integer range.
                if (dataLength == 16) {
                    dataOut += data[dataLength - 4] * 128;
                }

                return true;
            }

            return false;
        }

        /**
         * Check if the USB layer is ready.
         */
        bool isReady() {
            Usb.Task();
            if (Usb.getUsbTaskState() == USB_STATE_RUNNING) {
                return true;
            } else if (MS3::lastState != Usb.getUsbTaskState()) {
                MS3_DEBUG(F("*** USB task state: "));
                MS3_DEBUG_AS(MS3::lastState = Usb.getUsbTaskState(), HEX);
                MS3_DEBUGLN(F("."));
                MS3::ready = false;
            }

            return false;
        }

    public:

        /**
         * Constructor.
         */
        MS3() : USBH_MIDI(&Usb) {}

        /**
         * Set up the USB layer.
         */
        bool begin() {
            if (Usb.Init() == -1) {
                MS3_DEBUG(F("*** USB init error! ***"));
                return false;
            }

            return true;
        }

        /**
         * Init the editor mode.
         */
        void setEditorMode(bool active = true) {
            MS3::send((byte *) HANDSHAKE);
            delay(MS3_WRITE_INTERVAL_MSEC);
            MS3::send((byte *) HANDSHAKE);
            delay(MS3_WRITE_INTERVAL_MSEC);
            byte data[1] = {(active) ? (byte) 0x01 : (byte) 0x00};
            MS3::send(P_EDIT, data, 1, MS3_WRITE);
            delay(INIT_DELAY_MSEC);
            MS3_DEBUGLN(F("*** Up and ready!"));
        }

        /**
         * This is the main function for both receiving and sending data when
         * there's nothing to receive.
         */
        byte update(unsigned long &parameter, int &data) {

            // Are we ready?
            if (MS3::isReady()) {
                if (!MS3::ready) {
                    MS3::ready = true;
                    return MS3_READY;
                }
            } else {
                return MS3_NOT_READY;
            }

            // Is there data waiting to be picked up?
            if (MS3::receive(parameter, data)) {
                MS3::nextMessage = millis() + MS3_RECEIVE_INTERVAL_MSEC;
                return MS3_DATA_RECEIVED;
            }

            // Check if we need to send out a queued item.
            queueItem item = {};
            if (MS3::nextMessage <= millis() && Queue.read(item)) {

                // Construct the data to send to the MS-3.
                byte input[item.dataLength] = {0};
                input[item.dataLength - 1] = item.data % (byte) 128;
                if (item.dataLength >= 2) {
                    input[item.dataLength - 2] = (item.data >= 128) ? (byte) 1 : (byte) 0;
                }

                // Send the queue item to the MS-3.
                MS3::send(
                    item.address,
                    input,
                    item.dataLength,
                    item.operation
                );

                // Store when the next message may be sent.
                MS3::nextMessage = millis() + (item.operation == MS3_READ ? MS3_READ_INTERVAL_MSEC : MS3_WRITE_INTERVAL_MSEC);
                return MS3_DATA_SENT;
            }

            // Are we done? Did we wait for the last message to finish?
            if (Queue.isEmpty()) {
                return (MS3::nextMessage > millis()) ? MS3_ALMOST_IDLE : MS3_IDLE;
            }

            // Nothing interesting happened.
            return MS3_NOTHING_HAPPENED;
        }

        /**
         * Set this single byte parameter on the MS-3. Optionally pad it with leading zero-bytes with a dataLength >= 1.
         */
        void write(const unsigned long address, byte data, byte dataLength = 1) {
            Queue.write(address, data, dataLength, MS3_WRITE);
        }

        /**
         * Tell the MS-3 to send us the value of this parameter.
         */
        void read(const unsigned long address, byte data) {
            Queue.write(address, data, 4, MS3_READ);
        }

        /**
         * Flush the queue if it's not empty.
         */
        void flushQueue() {
            if (!Queue.isEmpty()) {
                Queue.flush();
            }
        }
};

#endif
There is also the Queue.h but that doesn't seem to use anything USB related. If you need it it's available here: https://github.com/MrHaroldA/MS3

Basically, I think I need to find the equivalent usbhhost_t36.h function of each of the USB related usbh_midi.h function. Although some are different and have differing return types.

These are the functions from usbh_midi.h that I think I need to replace.

Code:
MS3::MS3() : USBH_MIDI(&Usb) {}

uint16_t countSysExDataSize(uint8_t *dataptr);

uint8_t SendSysEx(uint8_t *dataptr, uint16_t datasize, uint8_t nCable=0);

uint8_t RecvData(uint16_t *bytes_rcvd, uint8_t *dataptr);

uint8_t extractSysExData(uint8_t *p, uint8_t *buf);

uint8_t getUsbTaskState(void);

virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);

Would you know of suitable replacements? I've tried to do a few myself already. Such as replacing:
Code:
MS3::MS3() : USBH_MIDI(&Usb) {}
with:
Code:
  MS3() : MIDIDevice(&Usb) {}

but functions like SendSysEx in usbh_midi.h have a differing return type to usbhhost_t36.h (uint8_t vs void) and of course the return value is calculated based on specific internal implementation details, which is where I start to stumble on finding the usbhhost_t36.h equivalents.

The point of the MS3 library is to construct and send MIDI Sysex messages to a 'non-class compliant' USB device using an address and data (it then handles adding in the header, calculating the checksum and the footer), as well as receive them back to extract the address and data portions. It also has the accompanying Queue.h file to (obviously) hand a queue of the Sysex messages. So the Teensy has the host port cable hooked directly into the back of the Boss Katana guitar amp.

The MS3 library does a nice job, and works. I've had this code working with my old Arduino Mega brilliantly. It's just trying to swap it over to using the usbhhost_t36.h now that I've upgraded to Teensy!
 
Last edited:
Hi Steve,

I have a very similar project to you also built on the 4.1 with USB host.

I've managed to get changes sent out over the built in hub directly to the Katana but cant get incoming data working.

Did you get anywhere updating MS3.h ?
 
Hi Steve,

I have a very similar project to you also built on the 4.1 with USB host.

I've managed to get changes sent out over the built in hub directly to the Katana but cant get incoming data working.

Did you get anywhere updating MS3.h ?

I can't pretend that my modifications were the best or even the 'correct way' of changing the library... I recall a few changes I made that felt quite 'hacky' (here's looking at you, singleton instance just to handle a callback function)... so feel free to correct my work, but yes, I got it working.

View attachment MS3_Mod.zip

There's a comment in the MS3.h file for myself in the future. My controller code isn't yet able to handle bulk data transfers from the katana, so there is a guard in place in the MS3 library to prevent bulk data from being received. If your code does handle that, then you will need to remove those guards.

Also, it would be wicked to see your final code using the library if you're willing to share !
 
Brilliant! Thanks Steve.

I've been wrestling on and off with this for a year or so and "hacky" is definitely my coding g standard!!

If I can get it to work I'm happy to share.
 
Ok so baby steps.

I have your MS3 and pulled the Effects State example from https://github.com/MrHaroldA/MS3/tree/master/examples/effect_state

I'm pretty sure I've updated the effects params to the MkII varient I have.

The first compile gave a couple of data type mismatches that I sorted but I still get an error -

if (!MS3.begin()) {
^
could not convert 'MS3.MS3::begin()' from 'void' to 'bool'

I can comment the line out but then although it compiles and loads , I get nothing other then "Ready" in the serial monitor - even with debug on. I'm not even sure the hub is firing up currently with the test code.

Any suggestions ?
 
Ok so baby steps.

I have your MS3 and pulled the Effects State example from https://github.com/MrHaroldA/MS3/tree/master/examples/effect_state

I'm pretty sure I've updated the effects params to the MkII varient I have.

The first compile gave a couple of data type mismatches that I sorted but I still get an error -

if (!MS3.begin()) {
^
could not convert 'MS3.MS3::begin()' from 'void' to 'bool'

I can comment the line out but then although it compiles and loads , I get nothing other then "Ready" in the serial monitor - even with debug on. I'm not even sure the hub is firing up currently with the test code.

Any suggestions ?

Ah yeah, simple answer is just to remove that whole 'if' block and just call MS3.begin() instead.

To explain slightly, the previous MS3::begin() method had another 'init' function inside it related to the old USB lib, that returned a code (-1 for failure) and the MS3::begin() method also return true/false based on that value. The t36 host lib also has an init function (called 'begin'), except this one is void and doesn't report success or failure using the return value. And so there's no need for the MS3::begin() function to be a bool either.

Saying that, if you want the 'example codes' to work too, you could change that function back to a bool instead (change it in the .h and the .cpp files) and then just make it return true regardless.

P.S I'm not certain that the effect_state example will work directly without changes on the katana because the addresses will be different.
 
Ah yeah, simple answer is just to remove that whole 'if' block and just call MS3.begin() instead.

snip

P.S I'm not certain that the effect_state example will work directly without changes on the katana because the addresses will be different.



OMG !! it worked ! Straight call did it thanks so much for a quick reply!

I had already updated the example addresses as you say but without being able to properly compile I was sort of shooting blind.


Now to chop this test code into my master script
 
Hoorah! You / I / we probably should swap that begin back to a bool again so the existing examples / code would work without requiring change. I think changing it to:
Code:
bool MS3::begin() {
  myusb.begin();
  midiDevice.setHandleSysEx(receivedSysex);
  return isReady();
}

Might do the trick, but I'm not with my controller/amp to be able to test and check that.
 
Hoorah! You / I / we probably should swap that begin back to a bool again so the existing examples / code would work without requiring change. I think changing it to:
Code:
bool MS3::begin() {
  myusb.begin();
  midiDevice.setHandleSysEx(receivedSysex);
  return isReady();
}

Might do the trick, but I'm not with my controller/amp to be able to test and check that.


Code:
bool begin() {
     myusb.begin();
     midiDevice.setHandleSysEx(receivedSysex);
  return isReady();

Is closer but still return init errors. This is a little beyond me, I'm still bouncing that I got a reply from the amp !!
 
Back
Top