faulty transmission/retrieval of bluetooth data

I have a phone app in react native sending data over bluetooth to light a digital led stip.
When I change the slider the value is added to an array. if the array is greater than 0, it will shift from the array and send the value every 20ms.
The issue is that even if I send only 10 values a second it seems to process incorrectly and incorrect colors are displayed.

For testing purposes I have an array, 360 values, all are the same: 42. I am sending the values of the array one by one every 20ms. (even at 100ms interval the issue still occurs).

sendBatchValues = (deviceObject, writeService, writeChar) => {
		for (let i = 0; i < 361; i++) {
			this.dataToSend.push(45);
		}
		this.theInterval = setInterval(this.intervalCallBack, 20);
	}
	intervalCallBack = (value) => {
		let currentSliderValueToSend = this.dataToSend.shift();
		this.sendDataThroughService(currentSliderValueToSend, this.props.bluetooth.deviceObject, this.props.bluetooth.connectionData.writeServiceUUID, this.props.bluetooth.connectionData.writeCharacteristicUUID)
		if (this.dataToSend.length == 0) {
			clearInterval(this.theInterval);
		}
	}
	sendDataThroughService = (value, deviceObject, writeService, writeChar) => {
		value = Math.floor(value);
		let hsaValue = this.hslToRgb(value/360);
		let fullCommandRGB = "c:" + hsaValue[0] + "," + hsaValue[1] + "," + hsaValue[2] + ";";
		let encodedString = btoa(fullCommandRGB);
		if(Object.keys(deviceObject).length > 0) {
			deviceObject.writeCharacteristicWithoutResponseForService(writeService, writeChar, encodedString);
		}
	}

and on the arduino I am processing the data by splitting on : , and ;
first value is the command, second third and forth and the red green and blue. I send those values to the function that changes the led strip.

void loop() {
  while (mySerial.available () > 0) {
    processIncomingByte (mySerial.read ());  
  }
  if (_patternLoop != NULL) {
  //    Serial.println("pointer has been set - now looping a pattern");
    _patternLoop();
  }
}


const unsigned int MAX_INPUT = 50;

void processIncomingByte (const byte inByte) {
  static int parse_the_string = 0;
  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];
  static unsigned int input_pos = 0;
  switch (parse_the_string) {
    case 0:
      switch (inByte) {
        case ':':
          commandString [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++; 
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            commandString [input_pos++] = inByte;
          break;
      }
      break;
    case 1:
      switch (inByte) {
        case ',':   // end of text
          red [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++; 
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            red [input_pos++] = inByte;
          break;
      }
      break;
    case 2:
      switch (inByte) {
        case ',':   // end of text
          green [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            green [input_pos++] = inByte;
          break;
      }
      break;
    case 3:
      switch (inByte) {
        case ';':   // end of text
          blue [input_pos] = '\0';  // terminating null byte
          // terminator reached! process input_line here ...
          process_data (commandString, red, green, blue);
          input_pos = 0;
          parse_the_string = 0; 
          break;
        case '\r':   // discard carriage return
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            blue [input_pos++] = inByte;
          break;
      }  // end of switch
      break;
    default:
      break;
  }
}


void process_data (const char * commandString, const char * red, const char * green, const char * blue) {
  int redValue = atoi(red) - 255;
  int greenValue = atoi(green) - 255;
  int blueValue = atoi(blue) - 255;
  redValue = abs(redValue);
  greenValue = abs(greenValue);
  blueValue = abs(blueValue);
  manuallyChangeBladeColor(redValue, greenValue, blueValue);
}

I uploadeda video showing that, when sending the same value 360 times every 20ms, it glitches and shows the wrong value.

What options do I have to improve this/ avoid the glitch.

Arduino code is incomplete.

Please post one or two examples of the messages that are sent to the Arduino.

And post the complete Arduino program.

...R
Serial Input Basics - simple reliable ways to receive data.

first tab

#include <Wire.h>
#include <SparkFunSX1509.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN            6
#define NUMPIXELS      60
//144
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8); // RX, TX 

typedef void (*voidFuncPtr)();// Create a type to point to a funciton.
static voidFuncPtr  _patternLoop;

const byte SX1509_ADDRESS = 0x3E;  // SX1509 I2C address

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
SX1509 io;

byte leds[] = {8, 9, 10, 11, 12, 13, 14, 15, 7, 6, 5};


int redbrightlvl = 225;                  // starting color will be yellow
int greenbrightlvl = 255;
int bluebrightlvl = 0;
int currentGreenValue[150];
int currentBlueValue[150];
int currentRedValue[150];

int sideA = 29;
int sideB =30;
int LedsHaveBeenSet = 0;

void setup() {
  Serial.begin(57600);
  //setting up the hm10 blue chip
  mySerial.begin(57600); //required when using the hm-10 with an arduino nano
  mySerial.listen();
  //setting up the i/o expander for the 3 led strips
  if (!io.begin(SX1509_ADDRESS)) {
    while (1) ; // If we fail to communicate, loop forever.
  }
  //setting led colors of each strip to off
  for (int indx = 1; indx < 16; indx++) {
    io.pinMode(indx, ANALOG_OUTPUT);
    io.analogWrite(indx, 255);
  }
  //setting up digital led strip
  pixels.begin();
  setBladeBrightness(15);
  for (int i = 0; i < 60; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
  pixels.show();
  //starting with the "ult" pattern for the led strip
  setupULT();
}

void loop() {
  while (mySerial.available () > 0) {
    processIncomingByte (mySerial.read ());  
  }
  if (_patternLoop != NULL) {
    //continue updating the digital led strip
    _patternLoop();
  }
}


void setPointer(voidFuncPtr loopFunc) {
    _patternLoop =  loopFunc;
} 

void setBladeBrightness(int brightLevel) {
  pixels.setBrightness(brightLevel);
}



const unsigned int MAX_INPUT = 50;
//process incoming data from the bluetooth chipp
void processIncomingByte (const byte inByte) {
  static int parse_the_string = 0;
  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];
  static unsigned int input_pos = 0;
  switch (parse_the_string) {
    case 0:
      switch (inByte) {
        case ':':
          commandString [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++; 
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            commandString [input_pos++] = inByte;
          break;
      }
      break;
    case 1:
      switch (inByte) {
        case ',':   // end of text
          red [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++; 
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            red [input_pos++] = inByte;
          break;
      }
      break;
    case 2:
      switch (inByte) {
        case ',':   // end of text
          green [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            green [input_pos++] = inByte;
          break;
      }
      break;
    case 3:
      switch (inByte) {
        case ';':   // end of text
          blue [input_pos] = '\0';  // terminating null byte
          // terminator reached! process input_line here ...
          process_data (commandString, red, green, blue);
          input_pos = 0;
          parse_the_string = 0; 
          break;
        case '\r':   // discard carriage return
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            blue [input_pos++] = inByte;
          break;
      }  // end of switch
      break;
    default:
      break;
  }
}


void process_data (const char * commandString, const char * red, const char * green, const char * blue) {
  int redValue = atoi(red) - 255;
  int greenValue = atoi(green) - 255;
  int blueValue = atoi(blue) - 255;
  redValue = abs(redValue);
  greenValue = abs(greenValue);
  blueValue = abs(blueValue);
  Serial.println("value ->");
  Serial.print("red: ");
  Serial.println(redValue);
  Serial.print("green: ");
  Serial.println(greenValue);
  Serial.print("blue: ");
  Serial.println(blueValue);
  manuallyChangeBladeColor(redValue, greenValue, blueValue);
}
int delayval = 10; // delay for half a second

int transition = 1;
bool runULT = false;

void manuallyChangeBladeColor(int red, int green, int blue) {
  Serial.println("manually changing");
  redbrightlvl = red;                  // starting color will be yellow
  greenbrightlvl = green;
  bluebrightlvl = blue;
  setPointer(loopULT);
  runULT = false;
}

void setupULT() {
  redbrightlvl = 225;                  // starting color will be yellow
  greenbrightlvl = 255;
  bluebrightlvl = 0;
  transition = 1;
  setPointer(loopULT);
  runULT = true;
}


void loopULT() {
  for(int i=LedsHaveBeenSet; i>=0;i--){
    //the pattern starts in the middle of the strip, shifting the color down the left and right side of the strip
    if(i==0){
      currentGreenValue[sideA] = greenbrightlvl;
      currentRedValue[sideA] = redbrightlvl;
      currentBlueValue[sideA] = bluebrightlvl;
      
      currentGreenValue[sideB] = greenbrightlvl;
      currentRedValue[sideB] = redbrightlvl;
      currentBlueValue[sideB] = bluebrightlvl;  
    }
    else{
      currentGreenValue[sideA - i] = currentGreenValue[sideA - i + 1];
      currentBlueValue[sideA - i] = currentBlueValue[sideA - i + 1];
      currentRedValue[sideA - i] = currentRedValue[sideA - i + 1];

      currentGreenValue[sideB + i] = currentGreenValue[sideB + i - 1];
      currentBlueValue[sideB + i] = currentBlueValue[sideB + i - 1];
      currentRedValue[sideB + i] = currentRedValue[sideB + i - 1];
    }
  }
  if(LedsHaveBeenSet < 29){
    LedsHaveBeenSet++;
  }
  for(int k=0; k <= LedsHaveBeenSet; k++){
    pixels.setPixelColor(sideA -k, pixels.Color(currentRedValue[sideA -k], currentGreenValue[sideA -k], currentBlueValue[sideA -k]));
    pixels.setPixelColor(sideB +k, pixels.Color(currentRedValue[sideB +k], currentGreenValue[sideB +k], currentBlueValue[sideB +k]));
    
  }
  pixels.show();
  delay(20);


  //if running the ULT pattern this automatically updates the color, other wise it will use  the color set via manuallyChangeBladeColor()
  if (runULT) {
    if (transition == 1) {
      yellowtogreen();
    }
    else if (transition == 2) {
      greentoblue();
    }
    else if (transition == 3) {
      bluetogreen();
    }
    else if (transition == 4) {
      greentoyellow();
    }
  }
}


void yellowtogreen(){
  if (redbrightlvl <= 11) {
    redbrightlvl = 0;
    transition = 2;
  } else {
    redbrightlvl -= 10;  
  }
}

void greentoblue(){
  if (greenbrightlvl <= 11) {
    greenbrightlvl = 0;
  } else {
    greenbrightlvl -= 10;
  }
  if (bluebrightlvl >= 244) {
    bluebrightlvl = 255;
  } else {
    bluebrightlvl += 10;
  }
  
  
  if (bluebrightlvl == 255 && greenbrightlvl == 0) {
    transition = 3;
  }
}

void bluetogreen(){
  
  if (greenbrightlvl >= 244) {
    greenbrightlvl = 255;
  } else {
    greenbrightlvl += 10;
  }
  if (bluebrightlvl <= 11) {
    bluebrightlvl = 0;
  } else {
    bluebrightlvl -= 10;
  }
  if (greenbrightlvl == 255 && bluebrightlvl == 0) {
    transition = 4;
//    Serial.println("GREEN -> red green blue");
//    Serial.println(redbrightlvl);
//    Serial.println(greenbrightlvl);
//    Serial.println(bluebrightlvl);
  }
}

void greentoyellow(){
  if (redbrightlvl >= 244) {
    redbrightlvl = 255;
    transition = 1;
//    Serial.println("YELLOW -> red green blue");
//    Serial.println(redbrightlvl);
//    Serial.println(greenbrightlvl);
//    Serial.println(bluebrightlvl);
  } else {
    redbrightlvl += 10;
  }
}

When I send the same value (45) many times this is what is printed to the monitor:

value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 255 blue: 64
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 64
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 255 blue: 64
value ->
red: 0 green: 64 blue: 255

Ziayakens:
first tab

I don't understand?

This seems to be a complex program with function pointers. Can you produce a short program that illustrates the problem?

In Reply #4 you say

When I send the same value (45) many times

Does that mean that you literally send the characters ( 4 5 ) with no linefeed for carriage return?

...R

      switch (inByte) {
        case ':':
          commandString [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            commandString [input_pos++] = inByte;
          break;
      }

A switch statement is appropriate when you have more than 2 cases.

  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];

This set of arrays does not mesh with you sending "45".

45 is the H value is a hls color. On the javascript side on the phone app. it converts 45 to rgb and constructs the string "c:255,191,0;" base64 encodes it, and sends it.
I have

  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];

and the switch case statement because it breaks apart the incoming message on : , and ;
using ; as the identifier to send the values off where "c" will eventually be used to identify which function to send the color to.

I am guessing the switch case that parses the data could be refactored but I had found someone elses example for parsing incoming serial data and modified it a bit to handle the format of my data.

I might have taken it too literally when you asked for complete code. Would you like me to make a new sketch containing only the code in question and repost the sketch?

base64 encodes it, and sends it.

So, what is being sent is NOT "c:255,191,0;", but you assume, on the receiver, that it is. I'm not understanding why.

Did I somehow miss the part where you base64 decode the text coming in one serial port and send it out to the serial port you are reading from in the code above?

I am using a third party package with react native to access bluetooth capabilities within the phone app, which if i recall correctly, needed to base64 encode the string before sending it.

Then I am using the hm10 with software serial. I am not super experienced with managing serial data, but I thought was on the right path.
When processing the data with processIncomingByte, despite sending the string as base64 encoded, I am able to parse the characters correctly. It just starts to breakdown when I send data too quickly.

You did not miss any decoding on the arduino side. I'm not clear how, but when I assume I am receiving the string (not base64 encoded) and parse each byte with that assumption, saving in the char arrays, it seems to match the assumption and get parsed as expected.

I am willing to attempt this process in a different manner if you believe I am doing something incorrectly and I can post the results. Should I try everything the same, but send the string without base64 encoding?

Should I try everything the same, but send the string without base64 encoding?

The string being sent, if you can read it, is NOT base64 encoded. Whether that happens because the phone app decodes it before sending, or for some other reason, I do not know.

With all your arrays, how much SRAM are you using? Do the arrays NEED to be that big?

What I would do is comment out all the code that USES the data, and just print the values parsed. Send the data as fast as possible. If that data all gets through, then it is the process of using the data that is causing problems. If not, then it is the process of sending or reading the data that is causing problems.

When we know which problem you are trying to solve, we can solve it faster.

I commented out the

//manuallyChangeBladeColor(redValue, greenValue, blueValue);

so that it only parses the data and prints to the console.

red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 19000 blue: 64

it seems to mess up about 2-10% of the time.

I supposed the r,g,b would not be more than 3 characters and I could limit the command to no more than 10 characters

I supposed the r,g,b would not be more than 3 characters and I could limit the command to no more than 10 characters

Your string looks, at max, like "c:rrr,ggg,bbb;". Looks more like 14 characters plus a terminating NULL.

Again, you are doing more than just reading the data. Just read, and print the strings. Do NOT convert to integers.

You want to pick up the speed of Serial. It does not have to match the speed of the software serial instance, which is running pretty fast, for the volume of data you are sending.

Using a board with more than one hardware serial port would be a better idea.

Ziayakens:
45 is the H value is a hls color. On the javascript side on the phone app. it converts 45 to rgb and constructs the string "c:255,191,0;" base64 encodes it, and sends it.

Make your Arduino program print out exactly what it receives before it attempts to parse it. Then post some examples of what it receives.

Telling us earlier that you "send the same value (45) many times" was not much help.

...R

sorry >_<
I brought it up to

Serial.begin(115200);

and have

void loop() {
  while (mySerial.available () > 0) {
    Serial.print(mySerial.read());
  }
  Serial.println("");
}

which gives me

995850535344495749444859 
 
995850535344495749444859995850535344495749444859 
995850535344 
49 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
995850 
53995850535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995859 
995850535344495749444859 
 
 
 
995850535344495749444859995850535344495749444859995850535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
9958505353444957 
4944 
995850535344495749444859 
 
995850535344495749444859 
 
99495749444859 
99585053534449574944485999585053 
53 
995850535344495749444859 
 
995850535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
995850 
53 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
995850535344495749444859 
9949444859 
995850535344495749444859 
 
995850535344495749444859 
9958505353444957494448 
59 
995850535344495749444859 
 
995850535344495749444859 
 
9949444859 
995850535344495749444859 
 
995850535344495749444859995850535344495749444859 
 
 
99585053534449 
5750535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
9958505353 
4449 
995850535344495749444859 
 
995850535344495749444859 
 
99535344495749444859 
995850535344495749444859 
995859 
995850535344495749444859 
 
995850535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
 
99444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859995850535344495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
9958505353444957 
49 
995850535344495749444859 
 
995850535344495749444859 
 
9944495749444859 
995850535344495749444859 
 
995850535344495749444859 
 
995850535344495749444859 
995850535344495749444859

Ziayakens:
which gives me

And is that you are expecting?

That simple program in Reply #14 makes no attempt to identify the start or end of the messages. Without knowing when a message starts and ends how can you parse it properly?

Have you carefully studied the examples in the link I gave you in Reply #2?

...R

    Serial.print(mySerial.read());

The read() method returns an int, not a char. Store the value in a char, and print the char.

I was recently working with an Arduino and HM-10 with a phone app. Characters would intermittently get dropped when sending to the Arduino. I could see that my app was (trying) to write all the characters but every now and then there would be one missing on the receiving end.

I fixed it by having the Arduino echo the characters back to the phone, with the app waiting until it receives characters before writing to the characteristic again.

If your problem is with transmission and not with parsing you might give that a shot.

oh thats unfortunate.. I see to be parsing it incorrectly.

with

void loop() {
  while (mySerial.available () > 0) {
    char d = mySerial.read();
    Serial.print(d);
    if (d == ';') {
      Serial.println("");      
    }
  }
}

It shows

c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;
c:255,191,0;

Robin2, yes I read that, In the main code I was trying to use ; as the indicator of the end of the data. But it seems im not parsing correctly

Ziayakens:
Robin2, yes I read that, In the main code I was trying to use ; as the indicator of the end of the data. But it seems im not parsing correctly

I reckon if you use the second example in my Serial Input Basics and change the end-marker to a semi-colon it will receive the data correctly.

Once you have received a message you can parse it with strtok() using the comma as the separator. The first group will include the c: and it looks like you can just ignore those first 2 characters - just replace them with the 0 character (ASCII 48).

...R