RGB C code challenge - Make LEDs pretty YOUR way


#1

I’m working an RGB LED controller, and have the core tech all done and ready to go. There is still work to be done with the laying out of the pcb, but all in good time.

What I don’t have is too many brilliant ideas on HOW the LED controller should behave, specifically, how it should look and respond to buttons being pressed in a way that is pleasing and pretty. So, if anyone has bright ideas on what they would like to see implemented in an LED controller, now is a great time to speak up and show me in code so it could be added. All you need is some imagination and some C skills.

First, an explanation of what you have to work with:



unsigned char button[8];
          /* each one is TRUE if the button is pressed, FALSE if not pressed. Button layout is as follows:
          0246
          1357    
           If a six button stick, 6 and 7 will always be unpressed. */

unsigned char rgb[8][3]; /* arrive for the rgb data you want displayed. rgb[button][channel] where the button number
          is the same as the layout above, and the channels are 0=Red, 1=Green, 2=Blue. If you want button 5 (Roundhouse)      
          to be brightest yellow:   rgb[5][0]=0xFF;rgb[5][1]=0xFF;rgb[5][2]=0; 
          Remains untouched from previous display; use clearRGBdata() to clear to all zeros before working if you dont
          want  to deal with data from previous frame */

unsigned char scratch[100]; /*playground. Can be used for anything you want, and will remain unchanged between
           frames. Will be cleared to all 0's when display mode is changed via the menu, or on power up. If you need more
          but you really shouldn't */

unsigned char primarycolor[3]; /* the user can use the menu to specify two colors of their choosing as their favorites,
          so routines can use these if they dont need full pallettes to deal with. primarycolor[0] is red, [1] is green, [2] is
           blue. */
unsigned char secondarycolor[3]; /* 2nd favorite color */
unsigned char isSixButton; /*will be true if a six button stick, false if 8 button stick*/


And functions to play with.



void hsvtorgb(unsigned int h, unsigned char s, unsigned char v, unsigned char *r, unsigned char *g, unsigned char *b);
          /* Takes HSV data and saves the equivalent RGB data where told. 
          'h' is the hue, a number from 0-360. 360=0=Red, 60=Yellow, 120=Green, 180=Cyan, 240=Blue, 300=Magenta
                     If number is >360, will be modulo'd down to 0-360.
          's' is Saturation (insert Wesker joke). 0=white, 255=full color.
          'v' is 'value'. 0==black, 255=full color.
        r, g, and b are where the values should go. Example to set Strong (button 2) to brightest  Magenta:
          hsvtorgb(300, 0xFF, 0xFF,     &rgb[2][0], &rgb[2][1], &rgb[2][2]);

void clearRGBdata(void); /* sets rgb[][] to all 0's. just a simple for loop */


Code should check whatever it needs to check, modify the rgb array as needed for that frame, and then exit. No waiting, no muss, no fuss. Local variables are perfectly welcome, but keep in mind they will likely be clobbered by the time the next frame rolls around, so save anything you want to save in the ‘scratch’ array so it’ll be there next frame. Don’t be afraid to go nuts though; each LED can be different colors, in a full 24 bit colorspace. There is plenty of processing time available, so math extensive formula are just fine. There is not an excess of memory though; try to avoid lengthy tables of data. Code will be executed every frame, at a very reliable 75Hz. Just to give an idea, my reading show less than 10% overhead by the interrupt routines, so you have well over 12ms of processing time available per frame at 8Mhz. Roughly 96,000 instructions. That’s a bunch.

Examples:
Pretty rainbow screensaver type from the youtube vid from last week. Button pressed have no affect in this mode.




void rainbow(void)
{ 
  unsigned int hue; 
  //our current color is saved in scratch. No need to check if its all zeros (initial condition), since we can safely start
  //with color 0.
  hue = (scratch[0]*(unsigned int)0x100)+scratch[1]; 
  //and loop back when we exceed 360.
  if(hue>359) {hue=0;scratch[0]=0;scratch[1]=0;}
  scratch[1]++;
  if(scratch[1]==0)scratch[0]++;	
  hue++; 
  if(isSixButton)
  { //6 buttons, so each color is 60 degrees from the previous
    hsvtorgb(hue,     0xFF, 0xFF, &rgb[0][0], &rgb[0][1], &rgb[0][2]);
    hsvtorgb(hue+60,  0xFF, 0xFF, &rgb[1][0], &rgb[1][1], &rgb[1][2]);
    hsvtorgb(hue+120, 0xFF, 0xFF, &rgb[2][0], &rgb[2][1], &rgb[2][2]);
    hsvtorgb(hue+180, 0xFF, 0xFF, &rgb[3][0], &rgb[3][1], &rgb[3][2]);
    hsvtorgb(hue+240, 0xFF, 0xFF, &rgb[4][0], &rgb[4][1], &rgb[4][2]);
    hsvtorgb(hue+300, 0xFF, 0xFF, &rgb[5][0], &rgb[5][1], &rgb[5][2]);
  }
  else
  { //8 buttons, so each color is 45 degrees from the previous
    hsvtorgb(hue,     0xFF, 0xFF, &rgb[0][0], &rgb[0][1], &rgb[0][2]);
    hsvtorgb(hue+45,  0xFF, 0xFF, &rgb[1][0], &rgb[1][1], &rgb[1][2]);
    hsvtorgb(hue+90,  0xFF, 0xFF, &rgb[2][0], &rgb[2][1], &rgb[2][2]);
    hsvtorgb(hue+135, 0xFF, 0xFF, &rgb[3][0], &rgb[3][1], &rgb[3][2]);
    hsvtorgb(hue+180, 0xFF, 0xFF, &rgb[4][0], &rgb[4][1], &rgb[4][2]);
    hsvtorgb(hue+225, 0xFF, 0xFF, &rgb[5][0], &rgb[5][1], &rgb[5][2]);
    hsvtorgb(hue+270, 0xFF, 0xFF, &rgb[6][0], &rgb[6][1], &rgb[6][2]);
    hsvtorgb(hue+315, 0xFF, 0xFF, &rgb[7][0], &rgb[7][1], &rgb[7][2]);
  }
	
}
/* Each time its run (each frame), the hue goes up slightly, shifting button[0] from red to orange to yellow slowly and smoothly. 
Each of the other buttons move the same way, but from different starting points in the color wheel. When button[0] is red, button[4] will be blue tinted.*/




//Pressed button starts red, and shifts while held. if released, goes dark immediately. 
//When repressed, continues from where it left off.
//an initialized scratch is fine since 0 is valid data. All rgb[] are written, so no need to clearRGBdata.
void color_cycle_when_held(void)
{
  unsigned char i;
  for(i=0;i<8;i++)
  {	
    if(button*) 
    { 
       hsvtorgb((scratch**2), 0xFF, 0xFF, &rgb*[0], &rgb*[1], &rgb*[2]);
                scratch*++; if(scratch*>179)scratch*=0;
    }
    else 
    {
      rgb*[0]=rgb*[1]=rgb*[2]=0;
    }
  } 
}


So, what would YOU like for an RGB controller to do?


#2

Make it “breathe”


#3

Just throwing this out there not even sure its even possible but is there anyway to have your led’s light up/pulsate to the game music or other music source


#4

Will the code (whatever it is) be called once every 1/60 of a second?
Is there access to the the stick inputs LRUD?


#5

Gathering ideas. Not sure if I can code them properly after years not using C. Well, we’ll see.


#6

WHoops, I’ll put that into the first post. 75Hz.


#7

Hmmm, I’ll have to work this out in C when I get home from work, but here’s a couple of my ideas:

  1. Each button has it’s own color. When it’s pressed, it lights up it’s own color, and the buttons immediately around it light up with it’s color as well, but dimmer. When multiple are pressed, it stacks and the buttons tint each other’s hues. It’d also be good to have a fade effect as they’re released, so that the colors don’t go away immediately. I’d have to experiment with colors to see what combines in an interesting fashion.

  2. Similar per-button color scheme, but this time each button has a “wave” that starts on the positive edge on the button itself, and pulses outward – the button pressed quickly fades in, then fades out as the adjacent buttons fade in and out with a lesser intensity – this carries along the buttons until the “ripple” falls off the other side – so a LP press would be seen (significantly softer, and after a short “travel time”) on 3P and 3K. It would hopefully the feel of the “impact” of the press being carried across the buttons. Perhaps it could even repeat itself if a button was held down for a certain amount of time (e.g. a second). Similarly, when “waves” collide they would add to each other as they pass each other.

I’ll probably just do a CSS mockup or something to visualize the effects, as I don’t have enough RGB LED’s on hand right now.


#8

@marcus

glad to see you are picking up the project again!

my suggestions (take em as you will) and learnings from sparky
[LIST=1]
[]store hex value for ease of use (end client)
[
]the hex value should be declared as char*
[]convert the char value to longfor internal usage
[LIST=1]
[]ex: char color = FFCC33;
[]long number = strtol(color, NULL, 16);
[
]i do this because it’s a sht load easier to manage a long than an array when using pointers
[/LIST]
[
]user timers and interrupts for polling instead of delay or sleep, or usleep
[]each pattern should take up 4 memory addressess, i represents the current pattern index
[LIST=1]
[
]0 + (4 x i) = pattern / index id
[]1 + (4 x i) = red intensity
[
]2 + (4 x i) = green intensity
[]3 + (4 x i) = blue intensity
[/LIST]
[
]don’t worry about 6 vs 8 buttons. develop as if 8 is default.
[/LIST]
here are a few methods (you will need to convert what you need from C++ to C)
and other useless bits you may find handy



/*
  primary, secondary and tertiary colors in long
*/
long r = 16711680;// red
long g = 65280;// green
long b = 255;// blue
long c = 65535;// cyan
long p = 16711935;// purple
long y = 16776960;// yellow
long w = 16777215;// white
long o = 0;// off




/*
  @RGB
  requires long from hex strtol(hex, NULL, 16);
  returns an array [red, green, blue]
  all array values are 0-255 intensity
*/
int* RGB(long number)
{
  int red = (number>>16);
  int green = ((number>>8) & 0xff);
  int blue = (number & 0xff);

  int rgb[] = {red, green, blue};
  return rgb;
}




/*
  convert number back to hex
*/
long number = (red * 65536) + (green * 256) + blue;
char buffer[12];
ltoa(number, buffer, 16);
char* color = buffer;


here is the recent working folder for Sparky that uses the above
https://sparky.svn.beanstalkapp.com/sparky/trunk/Arduino Files/rebuild/Sparky/

let me know if you need anything… …seriously
PCB layout, Code, Soda… …rubber ducking debugging even

Hardware wise
ISP header, please please please. 10 pin or 6 pin don’t care which, you can even put a sticker on to of the header that said ‘void if removed’ :slight_smile:


#9

This is probably full of syntax errors and bugs, but the concept seems neat to me:



void barberstripe(unsigned char foreground[3],unsigned char background[3], unsigned char t, unsigned char shift, unsigned char dutycycle) {
  int i,j,tmp;

  for(i=0;i<8;i++) {
      tmp=i*64;
      if(i&i) {
        tmp-=64;
        tmp+=t;
      }
      tmp&=255;
      if(tmp>=dutycycle) {
        for(j=0;j<3;j++) {
            rgb*[j]=background[j];
        }
      } else if(tmp<64 || dutycycle-tmp<64) { /* Ghetto anti-alias */
        if(tmp>dutycycle/2) {
            tmp=(dutycycle-tmp);
        }
        for(j=0;j<3;j++) {
            rgb*[j]=(background[j]*(64-tmp)+(foreground[j]*tmp))>>6;
        }
      } else {
        for(j=0;j<3;j++) {
            rgb*[j]=foreground[j];
        }
      }
  }
}

void barberpole () {
  unsigned char grey[]={0x8F,0x8F,0x8F};
  unsigned char red[]={0xFF,0x8F,0x8F};
  unsigned char blue[]={0x8F,0x8F,0xFF};
  unsigned char tmprgb[][]={{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}};
  int i,j;

  scratch[0]++; /* repeat counter */
  barberstripe(red,grey,scratch[0],64,85);
  for(i=0;i<8;i++) {
      for(j=0;j<3;j++) {
        tmprgb*[j]=rgb*[j];
      }
  }
  barberstripe(blue,grey,scratch[0]+128,64,85);
  for(i=0;i<8;i++) {
      for(j=0;j<3;j++) {
        rgb*[j]=(rgb*[j]>tmprgb*[j])?rgb*[j]:tmprgb*[j];
      }
  }
}

P.S. My apologies for the weird indents but the new SRK edit window is … less than ideal … and something between my editor and the C&P got mangled.


#10

As soon as I get my test rig moved over to the new house I’ll test it out and post up a vid. Im curious to see what it looks like.


#11

is there a way that you can have it read joy stick commands, and then do a lite sequence.

For example I
Shoryuken= (center butons burst from a brite red then fade to the outside buttons changing colors from a color spectrum leading to a fading out white.

I dont code I just solder and play with my wood :confused:


#12

“Abandon all support, ye who enter here.”

Does it even compile? The hope is that it will have a barber-pole like effect, though that’s probably a bit ambitious for an 8 pixel display.
I should probably brainstorm stuff…


#13

One of the earlier versions of Sparky had a console mode, whereby it would negate the user generated pattern with the coloring of the console you where playing in.


const int consoles[][8] = {
  {none,none,none,none,none,none,none,none}, // none
  {blue,yellow,white,white,green,red,white,white}, // xbox
  {purple,green,white,white,cyan,red,white,white}, // playstation
  {blue,yellow,cyan,white,green,red,white,white}, // tvc
  {blue,blue,blue,white,blue,white,white,white}, // wii
  {green,blue,white,white,yellow,red,white,white}, //snes
  {green,yellow,yellow,white,blue,yellow,yellow,white} // n64
};

Now if you manage to create a SuperCthulhu that has multi console support and auto drive the layout, your’re golden!


#14

I’ll have to play around with this when I have some free time.


#15

Just because, we need a Red (and maybe other colors) Cylon/ Knight Industry Two Thousand Red wave back and forth effect.
[media=youtube]WxE2xWZNfOc[/media]

Perhaps add the effect after a complete pattern the color changes or something.

Maybe the buttons from one side to the other cycle the colors of the Rainbow.
Puddle of ripping effect with a button press, coming from a pressed button. Both in Light and color.
Chasing Psychedelic lights

Also not really a suggestion but just to get you guys creative juices going

[media=youtube]VDtRCbOoTGA[/media]
I am not sure how you replicate that in 6 or 8 buttons.


#16

So, did my code compile?


#17

I had to specify the array size for tmprgb before it’d quit complaining, and had to drop the grey array down to 0’s; the changes just werent visible. But it compiled just fine.

Here’s what I’ve got so far:
[media=youtube]PPDQEmj-39A[/media]

Bring on the suggestions, please. Someone get Montoia in here, I could use artistic feedback.


#18

i will see what i can brew up. will this take or have the option for direction input from the joystick? i am wondering if i can code up something when it is in lights on mode, to have the leds pulse or change when a direction is entered. not sure if i can ponder a specific color if a move input is put in though…


#19

It doesn’t have access to stick signals, just the eight play buttons + start + back


#20

is there a way to set the toggle to start + select + jab or select + jab. since the select button may be used in training modes etc? - pondering another idea-