BLE data inconsistency with HM-10 and Arduino Nano

154 views Asked by At

We have a project that controls a led strip of 80, that is connected via mobile app. The components we used are as follows:

  • Arduino Nano Board
  • HM - 10 Bluetooth module
  • WS2812b Led Strip

On the app, user selects the colors(up to 5), animation (optional), animation speed and brightness. The selected configuration is transmitted to the BLE module with a certain throttle and debouncing. The color(selected on a color wheel on the app) and brightness transmits fine, without any issues.

The problem we encounter, is that when certain animation is active, if the user changes the animation speed via the app, the arduino part locks itself and will not accept any more commands.

To activate a configuration with animation, we send the data from app to arduino as follows:

<l255180200,240135068:089;04200>

The format is: < [mode] [colors(with ',')] : [brightness] ; [animationCode(2 digit)] [animationSpeed] >

At first, we had some inconsistencies with consecutive data, so we implemented the following for data acquisition:

void loop()
{
  // Read all serial data available, as fast as possible
  while (bleSerial.available() > 0)
  {
    char inChar = bleSerial.read();
    if (inChar == SOP)
    {
      index = 0;
      inData[index] = '\0';
      started = true;
      ended = false;
    }
    else if (inChar == EOP)
    {
      ended = true;
      break;
    }
    else
    {
      if (index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if (started && ended)
  {
    // The end of packet marker arrived. Process the packet

    Serial.println(inData);
    Serial.println(inData[0]);
    char mode = inData[0];

    if (mode == 'p')
    {
      togglePower(inData);
      finalizeRead();
      return;
    }

    if (mode == 'b')
    {
      changeBrightness(inData);
      finalizeRead();
      return;
    }
    if (mode == 't')
    {
      char *themeNo = strtok(NULL, ";");
      int themeCode = valueFromString(themeNo, 0, 2);
      theme(themeCode);
    }

    //    if (mode == 'e') {
    //      sound();
    //      return;
    //    }

    char *colorsWithBrightness = strtok(inData, ";");
    char *animation = strtok(NULL, ";");

    char *colors = strtok(colorsWithBrightness, ":");
    char *brightness = strtok(NULL, ":");

    custom(colors, brightness, animation);

    finalizeRead();
  }
}

void finalizeRead()
{
  // Reset for the next packet
  started = false;
  ended = false;
  index = 0;
  inData[index] = '\0';
}

int valueFromString(char *string, int start, int width)
{
  int value = 0;
  for (int n = 0; n < width; n++)
    value = value * 10 + string[start + n] - '0';

  return value;
}

So the custom function is called when the mode == 'l'. And in custom function, we perform as follows:

void custom(char *colors, char *brightness, char *animation)
{
  char *trueColors = strtok(colors, "l");
  char *colorsSplit = strtok(trueColors, ",");
  int colorCount = 0;
  uint32_t colorArray[5] = {};
  while (colorsSplit != NULL)
  {
    int r = valueFromString(colorsSplit, 0, 3);
    int g = valueFromString(colorsSplit, 3, 3);
    int b = valueFromString(colorsSplit, 6, 3);

    colorArray[colorCount] = strip.Color(r, g, b);
    colorCount++;
    colorsSplit = strtok(NULL, ",");
  }

  int ledsPerSegment = ledCount / colorCount;

  for (int n = 0; n < colorCount; n++)
  {
    int currentSegment = (n + 1) * ledsPerSegment;
    Serial.println(currentSegment);
    for (int z = n * ledsPerSegment; z < (n + 1) * ledsPerSegment; z++)
    {
      strip.setPixelColor(z, colorArray[n]);
    }
  }

  strip.setBrightness(atoi(brightness));
  strip.show();
  Serial.println("Done");

  if (animation)
  {
    int animationCode = valueFromString(animation, 0, 2);
    int animationSpeed = valueFromString(animation, 2, 3);
    Serial.println(animationSpeed);
    if (animationCode == 1)
      breath(animationSpeed, atoi(brightness));
    else if (animationCode == 7)
      pulse(animationSpeed, colorArray, colorCount);
  }
}

The problem occurs in pulse animation, which is like this:

void pulse(int wait, uint32_t colorArray[], int colorCount)
{
  black();
  while (bleSerial.available() <= 0)
  {
    for (i = 0; i < colorCount && bleSerial.available() <= 0; i++)
    {
      for (j = 0; j < ledCount / 2 && bleSerial.available() <= 0; j++)
      {
        strip.setPixelColor(39 - j, colorArray[i]);
        strip.setPixelColor(40 + j, colorArray[i]);
        strip.show();
        delay(wait);
      }
      black();
    }
  }
}

We initialize the animation without any issues using the following:

<l255180200,240135068:089;04200>

As soon as we adjust the animation speed from the app, we send about 2 new configurations per second, which is the same as above, only with different speed (last 3 characters before '>'). The arduino part randomly receives the data incorrectly, losing 2-3 characters, which is like <l2551800,240135068:089;04200>

The loss of characters usually occurs on different parts of the string, but always consecutive characters are misread happen each time. Also, sometimes we get a backwards question mark. We are not sure where we implement wrong, so any help is appreciated on solving this issue.

Thanks!

0

There are 0 answers