I've built an led strip controller using arduino mega. On arduino side serial communications code works like this:
- Wait until Serial.available is > 0
- Read first byte via Serial.read and save it to command[] byte array
- Depending on its value, choose one of multiple commands and wait until enough bytes that encode arguments are waiting to be read, then read them into command[] byte array
- Process them accordingly
- Return to step one
And while i was sending commands by hand, everything was ok, but when i wrote a program that sends commands for me, two commands sent too quickly cause glitches, it feels like commands "collide"
Simplified arduino code:
#include <bitswap.h>
#include <chipsets.h>
#include <color.h>
#include <colorpalettes.h>
#include <colorutils.h>
#include <controller.h>
#include <cpp_compat.h>
#include <dmx.h>
#include <FastLED.h>
#include <fastled_config.h>
#include <fastled_delay.h>
#include <fastled_progmem.h>
#include <fastpin.h>
#include <fastspi.h>
#include <fastspi_bitbang.h>
#include <fastspi_dma.h>
#include <fastspi_nop.h>
#include <fastspi_ref.h>
#include <fastspi_types.h>
#include <hsv2rgb.h>
#include <led_sysdefs.h>
#include <lib8tion.h>
#include <noise.h>
#include <pixelset.h>
#include <pixeltypes.h>
#include <platforms.h>
#include <power_mgt.h>
FASTLED_USING_NAMESPACE
#include <String.h>
#define NUM_LEDS 131
#define DATA_PIN 11
CRGB leds[NUM_LEDS];
byte command[12];
bool manualshow = 1;
void setup() {
FastLED.addLeds<WS2812, DATA_PIN, BRG>(leds, NUM_LEDS);
randomSeed(analogRead(0));
Serial.begin(115200); //Baud rate does not affect glitched behavior
}
void loop() {
while(Serial.available() == 0){} //Wait until there is something in serial buffer
command[0] = Serial.read(); //Recieve command code
switch(command[0])
{
default:
Serial.write(255); //Write 255 back to sender, indicating wrong command code
break;
//////////////SET WHOLE STRIP. Format: mode, H, S, V. |OR| mode, R, G, B.
case 0:
while(Serial.available() < 4){}; //Wait for arguments
for(int i = 1; i < 5; i++)
{
command[i] = Serial.read(); //Read 4 arguments
}
/////////PUT LED CODE AFTER THIS/////////
/Processing command with FastLED library
if(command[1] == 0) // 0 = HSV 1 = RGB
{
for(int i = 0; i<=NUM_LEDS; i++)
{
leds[i] = CHSV(command[2],command[3],command[4]);
}
}
else
{
for(int i = 0; i<=NUM_LEDS; i++)
{
leds[i] = CRGB(command[2],command[3],command[4]);
}
}
if(manualshow){FastLED.show();}
Serial.write(0);
break;
//Other commands follow somilar structure
//////////////FILL GRADIENT . Format: mode, StartPoint, (Start color), End Point, (End color), DIR (0 - FWD, 1 = BKWD, 2 - SHRT, 3 = LNG)
case 1:
while(Serial.available() < 10){};
for(int i = 1; i <= 10; i++)
{
command[i] = Serial.read();
}
TGradientDirectionCode Dir;
Dir = command[10];
if(command[1] == 0) // 0 = HSV 1 = RGB
{
fill_gradient(leds,command[2],CHSV(command[3],command[4],command[5]),command[6],CHSV(command[7],command[8],command[9]), Dir);
Serial.write(1);
}
else
{
fill_gradient_RGB(leds,command[2],CRGB(command[3],command[4],command[5]),command[6],CRGB(command[7],command[8],command[9]), Dir);
Serial.write(1);
}
if(manualshow){FastLED.show();}
break;
case 2: //FILL SOLID Format: mode, startpos, endpos, (color)
while(Serial.available() < 6){};
for(int i = 1; i <= 6; i++)
{
command[i] = Serial.read();
}
if(command[1] == 0)
{
for(int i = command[2]; i <= command[3]; i++)
{
leds[i] = CHSV(command[4],command[5],command[6]);
}
}
else
{
for(int i = command[2]; i <= command[3]; i++)
{
leds[i] = CRGB(command[4],command[5],command[6]);
}
}
if(manualshow){FastLED.show();}
Serial.write(2);
break;
case 3: //SET ONE LED Format: mode, pos, (color)
while(Serial.available() < 5){};
for(int i = 1; i <= 5; i++)
{
command[i] = Serial.read();
}
if(command[1] == 0)
{
leds[command[2]] = CHSV(command[3],command[4],command[5]);
if(manualshow){FastLED.show();}
}
else
{
leds[command[2]] = CRGB(command[3],command[4],command[5]);
if(manualshow){FastLED.show();}
}
Serial.write(3);
break;
case 4: //SET MODE (AUTO/MANUAL) Format: mode (0 - auto, 1 - manual)
while(Serial.available() < 1){};
command[1] = Serial.read();
if(command[1]==0){manualshow = 0;}else{manualshow = 1;}
break;
case 5: //SHOW
FastLED.show();
break;
case 6: //POLL Format: info
FastLED.show();
while(Serial.available() < 1){};
command[1] = Serial.read();
switch(command[1])
{
default:
Serial.write(0);
Serial.write(0);
break;
case 0:
Serial.write((byte)NUM_LEDS);
Serial.write(0);
break;
}
break;
}
}
What is wrong, and how can i properly implement byte "queue" so stuff wont collide