corneliusmunz / legoino

Arduino Library for controlling Powered UP and Boost controllers
MIT License
257 stars 34 forks source link

Lpf2HubEmulation - Port A not working #71

Open marco-bertani opened 2 years ago

marco-bertani commented 2 years ago

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:

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:

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

Can you help somehow?

corneliusmunz commented 2 years ago

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 commented 2 years ago

@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 commented 1 year ago

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 commented 1 year ago

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 https://github.com/RalfUhlig/legoino/commit/cdaa9e10b10507fa5d00cb19a377fd73c569a7be and here https://github.com/RalfUhlig/legoino/commit/667177da6a40c74991bb9fc92533427c7312b5e9 for details.