martinzw / THRII-direct-USB-pedalboard

A pedalboard that can send complete settings patches to a THRII guitar amplifier with direct USB-connection
31 stars 5 forks source link

Bluetooth LE Feasibility #5

Open bariskalem opened 3 months ago

bariskalem commented 3 months ago

Hi Martin,

Your detailed protocol document was extremely helpful to understand the SysEx. Thank you for that! I wanted to ask if you are aware of the feasibility of using BLE to send the SysEx data to the THR system.

I have an ESP32 devkit and using the ESP32-BLE-MIDI package to send SysEx to the amp. The idea is to create a preset selector pedal similar to a one available on the market; but cheaper. (see: AIRSTEP YT)

I'm sending over the following SysEx which I understand that they're acting like a handshake with the THR.

byte IDENTITY_REQUEST[]  = { 0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7 };

byte VERSION_REQUEST[]  = { 0xF0, // Request THR Amp version
                            0x00, 0x01, 0x0C, // Line6 
                            0x24, // THRII
                            0x02, 0x4D, // THR30IIWireless
                            0x00, // A or B
                            0x00, 0x00, 0x00, 0x07,  //
                            0x00, // 1st bitbucket
                            0x01, 0x00, 0x00, 0x00, // OP
                            0x00, 0x00, 0x00, // FB
                            0x00, // 2nd bitbucket
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Type?
                            0xF7}; 

byte HEADER[]  = { 0xF0, 
                   0x00, 0x01, 0x0C, // Line6 
                   0x24, // THRII
                   0x02, 0x4D, // THR30IIWireless
                   0x00, // A or B
                   0x01, 0x00, 0x00, 
                   0x07, 
                   0x00, 0x04, 0x00, 0x00, 
                   0x00, 0x04, 0x00, 
                   0x00,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                   0xF7}; 

byte MAGIC_KEY[]  = { 0xF0, 
                      0x00, 0x01, 0x0C, // Line6 
                      0x24, // THRII
                      0x02, 0x4D, // THR30IIWireless
                      0x00, // A or B
                      0x02, 0x00, 0x00, 
                      0x03, 
                      0x28, 0x72, 0x4D, 0x54, // Magic key for 1.4.4.0.a
                      0x00, 0x00, 0x00,
                      0xF7}; 

Unfortunately, even after connecting to the amp and sending these SysEx, I don't receive any SysEx events back from the amp.

Although, I can see that the ESP32 successfully connects, the amp doesn't react when I send the following preset change SysEx:

byte PRESET_2[]  = { 0xF0, // Request THR Amp version
                     0x00, 0x01, 0x0C, // Line6 
                     0x24, // THRII
                     0x02, 0x4D, // THR30IIWireless
                     0x01, // A or B
                     0x0E, 0x00, 0x00, 0x0B, 
                     0x00, 
                     0x0E, 0x00, 0x00, 0x00,
                     0x04, 0x00, 0x00, 
                     0x00, 
                     0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
                     0xF7}; //                              ^  Preset 2

My code basically utilizes the examples from the ESP32-BLE-MIDI package to create a BLE MIDI Client and send SysEx.

I appreciate your time on this!

Best, Barış

martinzw commented 3 months ago

Hi Bariş,I am on a holiday, so i can not check anything right now.Perhaps one hint:The usb cable must strictly not be connected to the PC, when trying to establish a BLE connection.Sounds obvious, but sometimes we struggle for stupid reasons...And i remember, that someone else already had successfully created a BLE Midi Sysex communication some time ago.Perhaps i find his posts in the history.Sunny greetings,Martin -------- Ursprüngliche Nachricht --------Von: Barış @.> Datum: 20.07.24 16:48 (GMT+01:00) An: martinzw/THRII-direct-USB-pedalboard @.> Cc: Subscribed @.***> Betreff: [martinzw/THRII-direct-USB-pedalboard] Bluetooth LE Feasibility (Issue #5) Hi Martin, Your detailed protocol document was extremely helpful to understand the SysEx. Thank you for that! I wanted to ask if you are aware of the feasibility of using BLE to send the SysEx data. I have an ESP32 devkit and using the ESP32-BLE-MIDI package to send SysEx to the amp. The idea is to create a preset selector pedal similar to a one available on the market; but cheaper. (see: AIRSTEP YT) I'm sending over the following SysEx which I understand that they're acting like a handshake with the THR. byte IDENTITY_REQUEST[] = { 0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7 };

byte VERSION_REQUEST[] = { 0xF0, // Request THR Amp version 0x00, 0x01, 0x0C, // Line6 0x24, // THRII 0x02, 0x4D, // THR30IIWireless 0x00, // A or B 0x00, 0x00, 0x00, 0x07, // 0x00, // 1st bitbucket 0x01, 0x00, 0x00, 0x00, // OP 0x00, 0x00, 0x00, // FB 0x00, // 2nd bitbucket 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Type? 0xF7};

byte HEADER[] = { 0xF0, 0x00, 0x01, 0x0C, // Line6 0x24, // THRII 0x02, 0x4D, // THR30IIWireless 0x00, // A or B 0x01, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7};

byte MAGIC_KEY[] = { 0xF0, 0x00, 0x01, 0x0C, // Line6 0x24, // THRII 0x02, 0x4D, // THR30IIWireless 0x00, // A or B 0x02, 0x00, 0x00, 0x03, 0x28, 0x72, 0x4D, 0x54, // Magic key for 1.4.4.0.a 0x00, 0x00, 0x00, 0xF7};

Unfortunately, even after sending these SysEx and connecting with the THR amp, I don't receive any SysEx back from the amp. My code basically utilizes the examples from the ESP32-BLE-MIDI package to create a BLE MIDI Client and send SysEx. I appreciate your time on this! Best, Barış

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

bariskalem commented 3 months ago

Hi Martin,

Thanks for the reply! I'll try it without the USB connection soon, and let you know. Do you mean that the BLE connection to the amp was made using your library?

Enjoy your vacation!

martinzw commented 3 months ago

Hi Barış,

there has been someone who built a pedal board with ESP32. But he did not send direct MIDI-Commands to THR30II but instead connected to the Android App via BLE:

https://github.com/radioactivetoy/BLEPedalboard

Looking at your Array definitions i think the first (IDENTITY_REQUEST) should be enough to provoke a reaction/answer from THR30II.

But i can not see, how you send this array as a SysEx message to the THR30II without your complete code.

As far as i have seen, the ESP32-BLE-MIDI package does not offer a "SendSysEx" - Method at all.

Can you send me your .ino?

bariskalem commented 2 months ago

Hi Martin,

I've also saw that project that connects to the Android App. Very interesting but I wanted to cut the middleman (the app) with my project.

In my initial issue post I've forgot to mention that I use the lathoub/Arduino-BLE-MIDI library to send SysEx data. This is the example that I've followed: SysEx_Send.ino

The following is my .ino

I'm using a M5StickC Plus2 devkit which provides commands to write text on screen and handle button presses.

// #include <Arduino.h>
#include <BLEMIDI_Transport.h>
// #include <hardware/BLEMIDI_Client_ESP32.h>
#include <hardware/BLEMIDI_ESP32_NimBLE.h>
#include "M5StickCPlus2.h"

#define MIDI_DEVICE_NAME "LE_THRII"

BLEMIDI_CREATE_INSTANCE(MIDI_DEVICE_NAME, MIDI)

unsigned long t0 = millis();
bool isConnected = false;

// ----------- SYSEX -----------
const byte IDENTITY_REQUEST[]  = { 0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7 };

byte VERSION_REQUEST[]  = { 0xF0, // Request THR Amp version
                            0x00, 0x01, 0x0C, // Line6 
                            0x24, // THRII
                            0x02, 0x4D, // THR30IIWireless
                            0x00, // A or B
                            0x00, 0x00, 0x00, 0x07,  //
                            0x00, // 1st bitbucket
                            0x01, 0x00, 0x00, 0x00, // OP
                            0x00, 0x00, 0x00, // FB
                            0x00, // 2nd bitbucket
                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Type?
                            0xF7}; 

byte HEADER[]  = { 0xF0, 
                   0x00, 0x01, 0x0C, // Line6 
                   0x24, // THRII
                   0x02, 0x4D, // THR30IIWireless
                   0x00, // A or B
                   0x01, 0x00, 0x00, 
                   0x07, 
                   0x00, 0x04, 0x00, 0x00, 
                   0x00, 0x04, 0x00, 
                   0x00,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                   0xF7}; 

byte MAGIC_KEY[]  = { 0xF0, 
                      0x00, 0x01, 0x0C, // Line6 
                      0x24, // THRII
                      0x02, 0x4D, // THR30IIWireless
                      0x00, // A or B
                      0x02, 0x00, 0x00, 
                      0x03, 
                      0x28, 0x72, 0x4D, 0x54, // Magic key for 1.4.4.0.a
                      0x00, 0x00, 0x00,
                      0xF7}; 

// After this, THR should send the following acknowledgment message:
// F0 00 01 0C 24 02 4D 00 01 00 00 0B 00 01 00 00 00 04 00 00 00 00 00 00 00 00 00 00 F7

// PRESET CHANGE MESSAGE
byte PRESET_2[]  = { 0xF0, // Request THR Amp version
                     0x00, 0x01, 0x0C, // Line6 
                     0x24, // THRII
                     0x02, 0x4D, // THR30IIWireless
                     0x01, // A or B
                     0x0E, 0x00, 0x00, 0x0B, 
                     0x00, 
                     0x0E, 0x00, 0x00, 0x00,
                     0x04, 0x00, 0x00, 
                     0x00, 
                     0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
                     0xF7}; //                              ^  Preset 2

bool sent_handshake = false;

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

  // StickC setup
  auto cfg = M5.config();
  StickCP2.begin(cfg);
  StickCP2.Display.setRotation(1);
  StickCP2.Display.setTextColor(ORANGE);
  StickCP2.Display.setTextDatum(middle_center);
  StickCP2.Display.setTextFont(&fonts::Orbitron_Light_24);
  StickCP2.Display.setTextSize(1);
  StickCP2.Display.drawString("Initialized", StickCP2.Display.width() / 2,
                              StickCP2.Display.height() / 2);

  // MIDI Setup
  BLEMIDI.setHandleConnected(OnConnected);
  BLEMIDI.setHandleDisconnected(OnDisconnected);
  MIDI.setHandleSystemExclusive(OnMidiSysEx);

  MIDI.begin();
}

void loop() {
  StickCP2.update();
  MIDI.read();
  if (isConnected && (millis() - t0) > 1000 && !sent_handshake) {
    Serial.println("SENDING HANDSHAKE");
    t0 = millis();
    MIDI.sendSysEx(sizeof(IDENTITY_REQUEST), IDENTITY_REQUEST, true);
    MIDI.sendSysEx(sizeof(VERSION_REQUEST), VERSION_REQUEST, true);
    MIDI.sendSysEx(sizeof(HEADER), HEADER, true);
    MIDI.sendSysEx(sizeof(MAGIC_KEY), MAGIC_KEY, true);
    sent_handshake = true;
    Serial.println("SENT HANDSHAKE");
  }  

  if (StickCP2.BtnA.wasPressed()) {
        if (isConnected && (millis() - t0) > 1000) {
            StickCP2.Speaker.tone(8000, 20);
            StickCP2.Display.clear();
            t0 = millis();
            MIDI.sendSysEx(sizeof(PRESET_2), PRESET_2, true);
            StickCP2.Display.drawString("Sent SysEx",
                                        StickCP2.Display.width() / 2,
                                        StickCP2.Display.height() / 2);
        }
        else {
          StickCP2.Speaker.tone(8000, 20);
          StickCP2.Display.clear();
          StickCP2.Display.drawString("Need connection",
                                        StickCP2.Display.width() / 2,
                                        StickCP2.Display.height() / 2);
        }
    }

}

// -----------------------------------------------------------------------------
// Device connected
// -----------------------------------------------------------------------------
void OnConnected() {
  isConnected = true;
  StickCP2.Display.clear();
  StickCP2.Display.drawString("Connected",
                                    StickCP2.Display.width() / 2,
                                    StickCP2.Display.height() / 2);
}

// -----------------------------------------------------------------------------
// Device disconnected
// -----------------------------------------------------------------------------
void OnDisconnected() {
  isConnected = false;
  sent_handshake = false;
  StickCP2.Display.clear();
  StickCP2.Display.drawString("Disconnected",
                                    StickCP2.Display.width() / 2,
                                    StickCP2.Display.height() / 2);
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void OnMidiSysEx(byte* data, unsigned length) {
  Serial.print(F("SYSEX: ("));
  Serial.print(length);
  Serial.print(F(" bytes) "));
  for (uint16_t i = 0; i < length; i++)
  {
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

The behaviour of the ESP32 board is that it connects to the Amp (the library prints out the message that it connected) and then disconnects randomly after some seconds with no response in between (no sign of SysEx being actually sent or received). It then does a cycle of random connects and disconnects indefinitely.

However I should mention that I've successfully sent SysEx data with a similar example by connecting the ESP32 board to my MacBook.

martinzw commented 2 months ago

OK, that looks different....

I experienced similar problems, when i tried out on my own following your initial posting. (see Platformio-Code BLE_MIDI_test, which i upload here in a "experiments" folder). But I think, the missing answer is a problem of the BLE-libraries. To proof this, i modified an Example for BLE-MIDI-Programming in Windows for Visual Studio and got the THR30II to answer me, though i did the same like in the ESP32-BLE test code. I put that in the "Experiments" folder as well.

At the moment i experience additional problems with the latest THR30II firmware (1.45.0c). There the answer to the request for the symbol table does not work the same way than before. So my programs do not work any more with the latest THR30II firmware.

Martin

BuhJuhWuh commented 2 months ago

At the moment i experience additional problems with the latest THR30II firmware (1.45.0c). There the answer to the request for the symbol table does not work the same way than before. So my programs do not work any more with the latest THR30II firmware.

Oh, wow, that's frustrating. Thanks for the warning. I'll stay away from the updates!

diegobz commented 1 month ago

@martinzw Have you been able to make any progress with THR30II firmware 1.45.0c?

I just upgraded it and noticed the problems you mentioned.

martinzw commented 1 month ago

No, i have not. On the one hand, i downgraded the firmware again to make it work again. And for this reason, i can not study the behaviour of the latest firmware.

On the other hand, i doubt that i would find a possibility to make the new firmware deliver the symbol table again. For me it looks like a bug, not just like a changed feature.

Mr. Kim from the forum wanted to report this bug to the team. But he ( and me) doubt, that Yamaha will fix it.

You could could however copy the symbol table from the THR Remote's folder and integrate it in your software as a workaround.

diegobz commented 1 month ago

I will check the THR Remote's folder for the symbol table, thanks for the tip.

But it indeed looks weird, the msgVals are not getting computed correctly it seems:

## Firmware 1.44

 08:38:03.604 -> 
Asking for Symbol table:
08:38:03.604 -> 

08:38:03.604 -> msg #24820 OK: dequ no ack but answ, t=3 n=39
08:38:03.604 -> msg #777 sent out
08:38:03.604 -> Main loop:19 Bytes received
08:38:03.604 -> ParseSysEx:  f0 0 1 c 24 2 4d 0 2 0 f f 0 1 0 0 0 1d 20 0 0 0 75 1 0 0 1d 20 1 0 0 0 0 0 0 4b 40 4b 6e 37 a 0 0 0 0 b 0 0 0 1c 3f 62 40 78 7 0 0 0 13 0 16 0 0 61 74 7d 1d 8 0 0 0 0 1c 0 0 0 68 4f 68 64 5d 7 0 0 0 0 24 0 0 0 49 74 60 30 69 5 0 0 0 2a b 0 0 0 34 1d 3 c 0 a 0 0 0 35 0 0 20 0 18 63 2f 67 b 0 0 0 0 41 0 0 0 25 20 1f 31 72 5 0 0 0 6 47 0 0 0 46 6c 43 40 4 8 0 0 0 50 0 1a 0 0 66 12 2f 1 7 0 0 0 0 58 0 0 0 58 1d 67 48 50 a 0 0 0 0 63 0 0 0 44 55 40 41 3a 4 0 0 0 68 c 0 0 0 11 6d 14 71 0 7 0 0 0 70 0 0 3c 0 15 36 12 f c 0 1 0 0 7d 0 0 0 6c 60 3f 6e 9 d 0 0 0 43 b 0 0 0 7c 21 77 2 70 5 0 0 0 11 0 12 0 0 1f 52 5 6 8 8 0 0 0 1a 0 0 0 38 36 68 f 46 7 0 0 21 0 22 0 0 0 52 3e 1 39 5a 7 0 0 0 2a a 0 0 0 7 6 6c 11 0 4 0 0 0 0 0 0 f7 0
08:38:03.604 -> msgVals Array:  1 201D 175 201D 0 376ECBCB A B F8623F1C 7 13 9DFD74E1 8 1C DD64E8CF 7 24 E9B07449 5 2A 8C831DB4 A 35 672F6398 B 41 72B11F25 5 47 8443ECC6 8 50 812F92E6 7 58 D0C8679D A 63 3AC15544 4 68 7114ED91 7 70 8F92B695 C 7D 9EEBFEC D 8B 70F7A17C 5 91 8605529F 8 9A C68FE836 7 A2 5A39BE52 7 AA 11EC0687 4

Versus


## Firmware 1.45

07:56:44.926 -> 
Asking for Symbol table:
07:56:44.926 -> 

07:56:44.926 -> msg #5 OK: dequ no ack but answ, t=12 n=5
07:56:44.926 -> msg #777 sent out
07:56:44.926 -> Main loop:61 Bytes received
07:56:44.926 -> ParseSysEx:  f0 0 1 c 24 2 4d 0 22 20 2 4 0 51 0 4c 65 76 65 6c 0 31 0 54 79 70 65 32 0 0 47 61 69 6e 32 5f 0 64 42 0 4c 65 76 65 0 6c 32 0 53 48 49 46 0 54 0 0 0 0 0 0 f7 0
07:56:44.926 -> msgVals Array:  654C0051 316C6576 70795400 47003265 326E6961 42645F 6576654C 5300326C 54464948 0
07:56:44.926 -> 
ERROR 1: Should not happen during dump!