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

Lpf2HubEmulation - Port A not working #71

Open
marco-bertani opened this issue Aug 27, 2022 · 4 comments
Open

Lpf2HubEmulation - Port A not working #71

marco-bertani opened this issue Aug 27, 2022 · 4 comments

Comments

@marco-bertani
Copy link

marco-bertani commented Aug 27, 2022

Hi,

I started playing around with PoweredUp just recently and I came across this awesome project. I am mostly interested un the Hub Emulation.

What I noticed is a weird behaviour with ports and the offcial PoweredUp app:

If I set Port A to TRAIN_MOTOR and Port B to TRAIN_MOTOR I get this:

  • motor commands to Port A do NOT work
  • motor commands to Port B do work
  • rgb commands to Hub LED do work

If I set Port A or Port B to device type LIGHT I can't make any of them work.

What I mean with "don't work" is that I enabled debug log on my ESP32, and when I press a button on the app in "Create Mode" no message is sent by the App to the Emulated Hub. Same thing for "Play Mode" (just note that I don't have any real LEGO hardware yet to know how to properly connect ports to make the Train dashboard work correctly)

I created a custom class that analyses and prints the content of received and sent messages based on the official protocol https://lego.github.io/lego-ble-wireless-protocol-docs/, and it looks like most messages sent by the Emulated Hub are correct.

I made a couple changes:

  • I turned this
        if (msgReceived[(byte)HubPropertyMessage::PROPERTY] == (byte)HubPropertyReference::ADVERTISING_NAME)
        {
          std::string payload;
          payload.push_back((char)HubPropertyReference::ADVERTISING_NAME);
          payload.append(_lpf2HubEmulation->getHubName());
          _lpf2HubEmulation->writeValue(MessageType::HUB_PROPERTIES, payload);
        }

into this

        if (msgReceived[(byte)HubPropertyMessage::PROPERTY] == (byte)HubPropertyReference::ADVERTISING_NAME)
        {
          std::string payload;
          payload.push_back((char)HubPropertyReference::ADVERTISING_NAME);
          payload.push_back((char)HubPropertyOperation::UPDATE_UPSTREAM);
          payload.append(_lpf2HubEmulation->getHubName());
          _lpf2HubEmulation->writeValue(MessageType::HUB_PROPERTIES, payload);
        }

to make it compliant.

  • I also added the response to PORT_INPUT_FORMAT_SETUP_SINGLE
      else if (msgReceived[(byte)MessageHeader::MESSAGE_TYPE] == (byte)MessageType::PORT_INPUT_FORMAT_SETUP_SINGLE)
      {
        // Gotta repsond with the same message, but different mesage type
        std::string payload = msgReceived.substr(3, msgReceived.length() - 3);  // remove the header
        _lpf2HubEmulation->writeValue(MessageType::PORT_INPUT_FORMAT_SINGLE, payload);
      }

but it does not solve the problem

Sometimes the App sends a PORT_INFORMATION_REQUEST message, sometimes it doesn't, and I don't understand why.

Can you help somehow?

@corneliusmunz
Copy link
Owner

Hi @marco-bertani ! Many thanks for your interest in this lib. Unfortunately I have not so much time in the last month to spent in the hub emulation feature. It turns out, that sometimes the emulation is not really reliable and I don't figure really out why. Can you share your custom class which analyzes and print out all the message traffic? This would be very helpful. I will try to evaluate your issue further after I will come back from my vacation. I will be back next week.

@marco-bertani
Copy link
Author

marco-bertani commented Aug 30, 2022

@corneliusmunz
Thank you for answering. I will definitely share my code as soon as I manage to have something usable. Currently it's not complete and not commented. It is very similar to what you did in Lpf2Hub::notifyCallback(...) but I print debug messages instead of parsing them to get a value. Also, it is usable both by Lpf2Hub and Lpf2HubEmulation since messages are the same.

I might consider merging the message decoding and getting parsed value into a unique static class to be recycled all around the code. I'll see...

A couple days a go I managed to make port A working (yay) by moving the "HUB_ATTACHED_IO" notifications from the loop() function to the characteristic subscription callback, with NO delay between events (somehow If I leave a 1 second delay it doesn't work).
Something like this:

class Lpf2HubServerCallbacks : public NimBLEServerCallbacks
{

  Lpf2HubEmulation *_lpf2HubEmulation;

public:
  Lpf2HubCharacteristicCallbacks(Lpf2HubEmulation *lpf2HubEmulation) : NimBLECharacteristicCallbacks()
  {
    _lpf2HubEmulation = lpf2HubEmulation;
  }

  void onWrite(NimBLECharacteristic *pCharacteristic)
  {  ...  }

  void onRead(NimBLECharacteristic *pCharacteristic)
  {  ...  }

  // I added this
  void onSubscribe(NimBLECharacteristic *pCharacteristic, ble_gap_conn_desc *desc, uint16_t subValue)
  {
    _lpf2HubEmulation->notifyAllAttachedDevices();
    _lpf2HubEmulation->isPortInitialized = true;
  }
}

...

// I added this in the main class
void Lpf2HubEmulation::notifyAllAttachedDevices()
{
  // 'pConnectedDevices' is the std::vector of attached devices
  for (int i = 0; i < pConnectedDevices.size(); i++)
  {
    notifyAttachedDevice(pConnectedDevices[i]);
  }
}

Of course there are other changes to make it work, like creating a Lpf2Device class to store port/device data when notifying.

I would really like to contribute to this project, as far as my little skills allow me😅.
P.S.: Where did you get the info on how to parse sensor values (Message Type 0x45)? Experimentation?

@RalfUhlig
Copy link

I think, I found the reason, why port A is not working. The io attachments to the ports seem to be too early. In the debug log I realized, that the attachment for port A is send, before the client is subscribed. So the app does not realize, that a device is attached at port A. In the main function of the HubEmulation sample, I extend the first delay to 2 seconds. Now the app has enough time to subscribe and to receive the io attachment fo port A. Of course, this is dirty. There should be a way to wait with the attachements, until a client is subscribed. We'll see. But I'm still trying to become more used with the code.

@RalfUhlig
Copy link

Ok. I think I found a better solution by adding a flag to indicate, if a client is subscripted. This can be used to wait before attaching io to the ports. So no delay is needed anymore to wait for the app. See RalfUhlig@cdaa9e1 and here RalfUhlig@667177d for details.

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

3 participants