forked from svn2github/led-library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathColorLamp.cpp
599 lines (526 loc) · 16.7 KB
/
ColorLamp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/*
* ColorLamp.h
*
* Copyright (c) 2011
* Remco Magielse & Serge Offermans
* Intelligent Lighting Institute (ILI), TU/e.
*
* All rights reserved. LAST UPDATE: 13-08-2012
*/
#include "ColorLamp.h"
/* CONSTRUCTORS */
/** Empty ColorLamp Constructor. If you use this, make sure to set the channel manually afterwards using setChannel();
this automatically assumes you use autoWrite (write to the arduino pins immediatily) and will set the pinMode for this channel to OUTPUT.
If you use another method (e.g. DMX), use the full constructor and set autoWrite to false **/
ColorLamp::ColorLamp( )
{
_x = 0;
_y = 0;
_hue = 0;
_saturation = 0;
_intensity = 0;
_red = 0;
_green = 0;
_blue = 0;
_channel = 1;
_channelRed = 1;
_channelGreen = _channelRed + 1;
_channelBlue = _channelRed + 2;
_on = true;
_autoWrite = true;
_commonAnode = false;
hueAnim = new Animation();
saturationAnim = new Animation();
}
/** Colorlamp Constructor. The first three parameters set channels for Red, Green and Blue.
If autowrite is set to true; the arduino will write the output values to the arduino pins.
Set autoWrite to false if you do not connect your LEDs to arduino pins directly
but use other channels (e.g. DMX, shift registers, TLC5940, etc.
If you have LEDs with a common anode (common +), you set that to true in order to invert the output values.
**/
ColorLamp::ColorLamp( uint32_t channelRed, uint32_t channelGreen, uint32_t channelBlue, bool autoWrite, bool commonAnode, uint32_t x, uint32_t y )
{
_x = x;
_y = y;
_hue = 0;
_saturation = 0;
_intensity = 0;
_red = 0;
_green = 0;
_blue = 0;
_channel = channelRed;
_channelRed = channelRed;
_channelGreen = channelGreen;
_channelBlue = channelBlue;
_on = true;
_autoWrite = autoWrite;
_commonAnode = commonAnode;
hueAnim = new Animation();
saturationAnim = new Animation();
if ( _autoWrite )
{
pinMode( _channelRed, OUTPUT );
pinMode( _channelGreen, OUTPUT );
pinMode( _channelBlue, OUTPUT );
}
_hasNewValue = true;
update();
}
/** Default Destructor **/
ColorLamp::~ColorLamp()
{
}
/* VOID FUNCTIONS */
/** Allows you to set the channel of the LED. if autoWrite is on, this is the Arduino pin that is actuated
If only one argument is supplied, the green and blue channel are the subsequent channel numbers
**/
void ColorLamp::setChannel( uint32_t channelRed, uint32_t channelGreen, uint32_t channelBlue )
{
if (channelGreen == 0 && channelBlue == 0) // This is the case if the user does not supply arguments for green and blue
{
channelGreen = channelRed + 1;
channelBlue = channelRed + 2;
}
_channel = channelRed;
_channelRed = channelRed;
_channelGreen = channelGreen;
_channelBlue = channelBlue;
if ( _autoWrite )
{
pinMode( _channelRed, OUTPUT );
pinMode( _channelGreen, OUTPUT );
pinMode( _channelBlue, OUTPUT );
}
}
/** This function immidatily sets the RED, GREEN and BLUE to the specified values.
Values are changed immediatily, but only actuated in the update() function.
When setting RGB; the values are first converted to HSB,
Conversion back to RGB happens during the update() function.
Any ongoing animations are stopped unless 'stopanimation' is set to false.
**/
void ColorLamp::setRGB( uint32_t r, uint32_t g, uint32_t b, bool stopAnimation )
{
if ( _red != r || _green != g || _blue != b )
{
uint32_t hsb[3] = { 0 , 0 , 0 };
uint32_t * hsbArray = rgbToHsb(r, g, b, hsb );
setHSB(hsbArray[0], hsbArray[1], hsbArray[2], stopAnimation);
}
}
/*
void ColorLamp::setRed( uint8_t r, bool stopAnimation )
{
uint8_t hsb[3] = { 0 , 0 , 0 };
uint8_t * hsbArray = rgbToHsb(r, _green, _blue, hsb );
setHSB(hsbArray[0], hsbArray[1], hsbArray[2], stopAnimation);
}
void ColorLamp::setGreen( uint8_t g, bool stopAnimation )
{
uint8_t hsb[3] = { 0 , 0 , 0 };
uint8_t * hsbArray = rgbToHsb(_red, g, _blue, hsb );
setHSB(hsbArray[0], hsbArray[1], hsbArray[2], stopAnimation);
}
void ColorLamp::setBlue( uint8_t b, bool stopAnimation )
{
uint8_t hsb[3] = { 0 , 0 , 0 };
uint8_t * hsbArray = rgbToHsb(_red, _green, b, hsb );
setHSB(hsbArray[0], hsbArray[1], hsbArray[2], stopAnimation);
} */
/** This function immidatily sets the hue, saturation and intensity to the specified values.
Values are changed immediatily, but only actuated in the update() function.
Any ongoing animations are stopped unless 'stopAnimation' is set to false.
**/
void ColorLamp::setHSB( uint32_t h, uint32_t s, uint32_t b, bool stopAnimation )
{
if ( _hue != h || _saturation != s || _intensity != b )
{
_hue = constrain( h, 0, 4095 );
_saturation = constrain( s, 0, 4095 );
_intensity = constrain( b, 0, 4095 );
_hasNewValue = true;
if (stopAnimation)
{
intensityAnim->stopAnimation();
hueAnim->stopAnimation();
saturationAnim->stopAnimation();
}
}
}
/** This function immidatily sets the Hue to the specified value and
Values are changed immediatily, but only actuated in the update() function.
maintains the other current variables. Any ongoing hue animation is stopped unless 'stopAnimation' is set to false.
**/
void ColorLamp::setHue( uint32_t h, bool stopAnimation )
{
if( h != _hue )
{
_hue = constrain( h, 0, 4095 );
_hasNewValue = true;
if (stopAnimation)
{
hueAnim->stopAnimation();
}
}
}
/** This function immidatily sets the saturation to the specified value and
maintains the other current variables. Any ongoing saturation animation is stopped unless 'stopAnimation' is set to false.
Values are changed immediatily, but only actuated in the update() function.
**/
void ColorLamp::setSaturation( uint32_t s, bool stopAnimation )
{
if( s != _saturation )
{
_saturation = constrain( s, 0, 4095 );
_hasNewValue = true;
if (stopAnimation)
{
saturationAnim->stopAnimation();
}
}
}
/** This function allows an animation in RGB terms.
When animating RGB; the values are first converted to HSB
Conversion back to RGB happens during the update function.
**/
void ColorLamp::rgbTo( uint32_t rTo, uint32_t gTo, uint32_t bTo, uint32_t duration )
{
uint32_t hsb[3] = { 0 , 0 , 0 };
uint32_t * hsbArray = rgbToHsb(rTo, gTo, bTo, hsb );
hsbTo(hsbArray[0], hsbArray[1], hsbArray[2], duration);
}
/*
void ColorLamp::redTo( uint8_t rTo, uint32_t duration )
{
uint8_t hsb[3] = { 0 , 0 , 0 };
uint8_t * hsbArray = rgbToHsb(rTo, _green, _blue, hsb );
hsbTo(hsbArray[0], hsbArray[1], hsbArray[2], duration);
}
void ColorLamp::greenTo( uint8_t gTo, uint32_t duration )
{
uint8_t hsb[3] = { 0 , 0 , 0 };
uint8_t * hsbArray = rgbToHsb(_red, gTo, _blue, hsb );
hsbTo(hsbArray[0], hsbArray[1], hsbArray[2], duration);
}
void ColorLamp::blueTo( uint8_t bTo, uint32_t duration )
{
uint8_t hsb[3] = { 0 , 0 , 0 };
uint8_t * hsbArray = rgbToHsb(_red, _green, bTo, hsb );
hsbTo(hsbArray[0], hsbArray[1], hsbArray[2], duration);
} */
/** This function is used for animating to a desired HSB value. The duration of the animation can be set in millis().
shortcutThroughZero allows use of the hue color wheel as expected. If the shortest route from start value to end value goes through zero (red)
we will take this route by default. Set it to false if you wish to take the longer route.
**/
void ColorLamp::hsbTo( uint32_t hTo, uint32_t sTo, uint32_t bTo, uint32_t duration, bool shortcutThroughZero )
{
hueAnim->startAnimation( _hue, constrain(hTo, 0, 4095), duration, shortcutThroughZero );
saturationAnim->startAnimation( _saturation, constrain(sTo, 0, 4095), duration );
intensityAnim->startAnimation( _intensity, constrain(bTo, 0, 4095), duration );
}
/** This function is used for animating to a desired HUE value while maintaining Saturation and Brightness values.
The duration of the animation can be set in millis().
shortcutThroughZero allows use of the hue color wheel as expected. If the shortest route from start value to end value goes through zero (red)
we will take this route by default. Set it to false if you wish to take the longer route.
**/
void ColorLamp::hueTo( uint32_t hTo, uint32_t duration, bool shortcutThroughZero )
{
hueAnim->startAnimation( _hue, constrain(hTo, 0, 4095), duration, shortcutThroughZero );
}
/** This function is used for animating to a desired Saturation value while maintaining Hue and Brightness values.
The duration of the animation can be set in millis().
**/
void ColorLamp::saturationTo( uint32_t sTo, uint32_t duration )
{
saturationAnim->startAnimation( _saturation, constrain(sTo, 0, 4095), duration );
}
/** Tells the program you are using LEDs with a common anode (common +), if set to true (default = false).
This will invert the output values. If autoWrite == true, the arduino will make the ouput pins LOW in order to
turn the LEDs on. If autoWrite == false, getRed(), getGreen() and getBlue() will return the inverted value (0 if it is full on).
**/
void ColorLamp::setCommonAnode( bool commonAnode )
{
_commonAnode = commonAnode;
}
/** Sets the animation type for a colorLamp. The available animation types are LINEAR (no easing) and QUADRATIC.
QUADRATIC animations allow independant easing in and out **/
void ColorLamp::setAnimationType( uint8_t animType, bool easeIn, bool easeOut )
{
intensityAnim->setAnimationType( animType, easeIn, easeOut );
hueAnim->setAnimationType( animType, easeIn, easeOut );
saturationAnim->setAnimationType( animType, easeIn, easeOut );
}
/** CURRENTLY UNUSED -- Sets the ColorFade type for a colorLamp. The available fade types are HSB_FADE and RGB_FADE
In case of HSB, fade happen along the Hue Saturation and Brightness axis, which allows
you to go through a color wheel. In RGB mode the red green and blue values fade to their destination individually.
**/
void ColorLamp::setColorFadeType( uint8_t fadeType )
{
_colorFadeType = fadeType;
}
/** Update Function; should be called every loop to set, animate and actuate the lamps **/
void ColorLamp::update()
{
if( hueAnim->isAnimating() )
{
setHue( hueAnim->getValue(), false );
}
if( saturationAnim->isAnimating() )
{
setSaturation( saturationAnim->getValue(), false );
}
if( intensityAnim->isAnimating() )
{
setIntensity( intensityAnim->getValue(), false );
}
if ( _hasNewValue )
{
/* Update the RGB values based on HSB to reflect the changes for actuation
This overwrites the current RGB values, even if they were recently set.
However, this is not a problem because if an RGB value is set;
it is also converted to matching HSB values that are thus up-to-date.
*/
uint32_t rgb[3];
uint32_t * rgbArray = hsbToRgb(_hue, _saturation, _intensity, rgb );
_red = constrain( rgbArray[0], 0, 4095 );
_green = constrain( rgbArray[1], 0, 4095 );
_blue = constrain( rgbArray[2], 0, 4095 );
if( _autoWrite )
{
if ( !_commonAnode )
{
analogWrite(_channelRed, _red);
analogWrite(_channelGreen, _green);
analogWrite(_channelBlue, _blue);
}
else
{
analogWrite(_channelRed, 4095-_red);
analogWrite(_channelGreen, 4095-_green);
analogWrite(_channelBlue, 4095-_blue);
}
_hasNewValue = false;
}
}
}
/* INTEGER FUNCTIONS */
/** Returns the set channel for the RED LED **/
uint32_t ColorLamp::getChannelRed()
{
return _channelRed;
}
/** Returns the set channel for the GREEN LED **/
uint32_t ColorLamp::getChannelGreen()
{
return _channelGreen;
}
/** Returns the set channel for the BLUE LED **/
uint32_t ColorLamp::getChannelBlue()
{
return _channelBlue;
}
/** This function returns the current RED output value. Be careful that they are inverted if commonAnode is set to true! **/
uint32_t ColorLamp::getRed()
{
if ( !_commonAnode )
{
return _red;
}
else
{
return 4095-_red;
}
}
/** This function returns the current GREEN output value. Be careful that they are inverted if commonAnode is set to true! **/
uint32_t ColorLamp::getGreen()
{
if ( !_commonAnode )
{
return _green;
}
else
{
return 4095-_green;
}
}
/** This function returns the current GREEN output value. Be careful that they are inverted if commonAnode is set to true! **/
uint32_t ColorLamp::getBlue()
{
if ( !_commonAnode )
{
return _blue;
}
else
{
return 4095-_blue;
}
}
/** This function returns the current HUE output value. **/
uint32_t ColorLamp::getHue()
{
return _hue;
}
/** Returns the target value of the Hue animation
**/
uint32_t ColorLamp::getTargetHue()
{
return hueAnim->getEndValue();
}
/** This function returns the current SATURATION output value. **/
uint32_t ColorLamp::getSaturation()
{
return _saturation;
}
/** Returns the target value of the Saturation animation
**/
uint32_t ColorLamp::getTargetSaturation()
{
return saturationAnim->getEndValue();
}
/** This function returns the current INTENSITY output value. **/
uint32_t ColorLamp::getBrightness()
{
return _intensity;
}
/** This function converts RGB to HSB and is based on the one implemented
by robert Atkins in the RGB Converter Library
https://github.com/ratkins/RGBConverter
*/
uint32_t * ColorLamp::rgbToHsb(uint32_t r, uint32_t g, uint32_t b, uint32_t hsb[] )
{
float rd = (float) r/4095;
float gd = (float) g/4095;
float bd = (float) b/4095;
float maxVal = max(rd, max(gd, bd));
float minVal = min(rd, min(gd, bd));
float h = maxVal;
float s = maxVal;
float v = maxVal;
float d = maxVal - minVal;
s = maxVal == 0 ? 0 : d / maxVal;
if (maxVal == minVal) {
h = 0; // achromatic
} else {
if (maxVal == rd) {
h = (gd - bd) / d + (gd < bd ? 6 : 0);
} else if (maxVal == gd) {
h = (bd - rd) / d + 2;
} else if (maxVal == bd) {
h = (rd - gd) / d + 4;
}
h /= 6;
}
h *= 4095;
s *= 4095;
v *= 4095;
hsb[0] = uint32_t(h);
hsb[1] = uint32_t(s);
hsb[2] = uint32_t(v);
return hsb;
}
/** This function converts RGB to HSB and is based on the one implemented
by Elco Jacobs in the ShiftPWM Library
https://github.com/elcojacobs/ShiftPWM
*/
/*uint32_t * ColorLamp::hsbToRgb( uint32_t h, uint32_t s, uint32_t v, uint32_t rgb[] )
{
uint32_t r,g,b;
//uint32_t hue = map(h,0,4095,0,359);
float hue = map(h,0,4095,0,359);
uint32_t phase = hue/60.0;
uint32_t bottom = ( (4095 - s) * (float(v) / 4095.0));
uint32_t top = v;
uint32_t rising = ((top-bottom) *(hue%60 ) ) / 60 + bottom;
uint32_t falling = ((top-bottom) *(60-hue%60) ) / 60 + bottom;
switch(phase) {
case 0:
r = top;
g = rising;
b = bottom;
break;
case 1:
r = falling;
g = top;
b = bottom;
break;
case 2:
r = bottom;
g = top;
b = rising;
break;
case 3:
r = bottom;
g = falling;
b = top;
break;
case 4:
r = rising;
g = bottom;
b = top;
break;
case 5:
r = top;
g = bottom;
b = falling;
break;
}
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
return rgb;
}
*/
uint32_t * ColorLamp::hsbToRgb( uint32_t h, uint32_t sat, uint32_t bri, uint32_t rgb[] )
{
int32_t red_val;
int32_t green_val;
int32_t blue_val;
uint32_t hue = map(h,0,4095,0,12284);
if (hue < 4095) {
red_val = (5591040 - sat * (hue - 2730)) >> 12;
green_val = (5591040 - sat * (1365 - hue)) >> 12;
blue_val = (5591040 - sat * 1365) >> 12;
}
else if (hue < 8190) {
red_val = (5591040 - sat * 1365) >> 12;
green_val = (5591040 - sat * (hue - 6825)) >> 12;
blue_val = (5591040 - sat * (5460 - hue)) >> 12;
}
else {
red_val = (5591040 - sat * (9555 - hue)) >> 12;
green_val = (5591040 - sat * 1365) >> 12;
blue_val = (5591040 - sat * (hue - 10920)) >> 12;
}
rgb[0] = ((bri + 1) * red_val) >> 12;
rgb[1] = ((bri + 1) * green_val) >> 12;
rgb[2] = ((bri + 1) * blue_val) >> 12;
return rgb;
}
/* BOOL FUNCTIONS */
/** This function returns true if any animation (either HUE, SATURATION, BRIGHTNESS) is ongoing in this ColorLamp **/
bool ColorLamp::isAnimating()
{
if ( !intensityAnim->isAnimating() && !hueAnim->isAnimating() && !saturationAnim->isAnimating() )
{
return false;
}
else
{
return true;
}
}
/** Returns true if the supplied parameter (HUE, SATURATION, BRIGHTNESS) is animating **/
bool ColorLamp::isAnimating(uint8_t param)
{
switch ( param )
{
case PARAM_INTENSITY:
return intensityAnim->isAnimating();
break;
case PARAM_HUE:
return hueAnim->isAnimating();
break;
case PARAM_SATURATION:
return saturationAnim->isAnimating();
break;
}
}