Adafruit VL6180X , non blocking code

Hi,

On uint8_t Adafruit_VL6180X::readRange(void) there are two while statments. How can I change this for something that is non blocking the loop?

This is a bit advanced for me.

You're asking us to hack an Adafruit library for you?

You need to learn how to untangle blocking code using state machines.

Here in this case the code is pretty self explanatory :

there is an initial active wait for the device to be ready

 // wait for device to be ready for range measurement
  while (! (read8(VL6180X_REG_RESULT_RANGE_STATUS) & 0x01));

so a new function would need to test that flag and return false or something until this is ready

Once ready the code initiates a range measurement

  // Start a range measurement
  write8(VL6180X_REG_SYSRANGE_START, 0x01);

this can be kept as is.

But then the code waits for the measure to be ready

  // Poll until bit 2 is set
  while (! (read8(VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x04));

so that would need again to return instantly until the data is ready.

When the data is ready, then it's a simple read and clean up, you can acquire the value

// read range in mm
  uint8_t range = read8(VL6180X_REG_RESULT_RANGE_VAL);

  // clear interrupt
  write8(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);

So the idea is to build a small state machine, embedded into a non blocking function, that would return false until the data is available and true where the data has been read.

I would do something like this (to add inside the library code and declared in the public methods)

boolean Adafruit_VL6180X::readRangeNoWait(uint8_t &range)
{
  static uint8_t _range_state = 0; // 0 = Idle. 1 = read requested, waiting for device to be ready. 2 = trigger read. 3 = waiting for range to be avail. 4=data is there
  static boolean dataReady;

  switch (_range_state) {
    case 0: // initiate a read
      dataReady = false;
      _range_state = 1;
      break;

    case 1: // wait for device to be ready for range measurement
      if ((read8(VL6180X_REG_RESULT_RANGE_STATUS) & 0x01)) _range_state = 2;
      break;

    case 2:// Start a range measurement
      write8(VL6180X_REG_SYSRANGE_START, 0x01);
      _range_state = 3;
      break;

    case 3:// wait for data to be available, Poll until bit 2 is set
      if ((read8(VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x04)) _range_state = 4;
      break;

    case 4:// read & cleanup, flag data is there
      range = read8(VL6180X_REG_RESULT_RANGE_VAL);      // read range in mm
      write8(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);      // clear interrupt
      _range_state = 0; // go back to Idle state
      dataReady = true;
      break;

    default: // should not happen!
      break;
  }
  return dataReady;
}

and you would use it like this in your loop()

uint8_t aRange;

...

// somewhere in the loop()

if (VL6180X.readRangeNoWait(aRange)) {
 // data ready, aRange is set with the right value

} else {
 // go do something else as the data was not ready

}

Typed here - totally untested! let us know if that works... really curious :slight_smile:

To J-M-L

Thanks, works like a charm :slight_smile: