-
Notifications
You must be signed in to change notification settings - Fork 0
/
led.cpp
468 lines (438 loc) · 13.9 KB
/
led.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
#include <iostream>
#include <stdint.h> //libary which includes uint16_t etc.
#include "config.h"
#include "led.hpp"
#include <pigpio.h>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>
#include <pthread.h>
#include <time.h> /* for the random function :time */
using namespace std;
using namespace led;
//init of static variables
int LED::pwmSteps = 1000;
int LED::fadeTime = 1000;
std::map<int, led::LED*> LED::ledMap;
//********++getter*****************
std::string LED::getColorCode()
{
return this->colorcode;
}
uint16_t LED::getPin()
{
return this->pin;
}
bool LED::IsColor()
{
return this->isColor;
}
bool LED::isFading()
{
return this->fading;
}
bool LED::isRandomlyFading()
{
return this->randomlyFading;
}
int LED::getCurrentBrightness()
{
return this->currentBrightness;
}
int LED::getTargetBrightness()
{
return this->targetBrightness;
}
int LED::getTrueColorMultipier()
{
return this->trueColorMultiplier;
}
int LED::getPwmSteps()
{
return LED::pwmSteps;
}
pthread_t LED::getFadeThread()
{
return this->fadeThread;
}
int LED::getFadeTime(void)
{
return LED::fadeTime;
}
//************************setter************************************************
void LED::setFadeTime(int newFadeTime)
{
//we won't accept smaller numbers because we dont want to waste too much cpu power
if (newFadeTime > 0)
{
LED::fadeTime = newFadeTime;
}
else
{
std::cerr << "please set a fadetime greater than zero" << std::endl;
}
}
void LED::setColorCode(std::string new_colorcode)
{
this->colorcode = new_colorcode;
}
void LED::setTrueColorMultipier(int new_Multiplier)
{
trueColorMultiplier = 0;
if (new_Multiplier > 0 && new_Multiplier < 100)
{
this->trueColorMultiplier = new_Multiplier;
}
}
void LED::setPin(uint16_t newpin)
{
this->pin = newpin;
}
void LED::setIsColor(bool newisColor)
{
this->isColor = newisColor;
}
void LED::setCurrentBrightness(int new_cBrightness)
{
if (new_cBrightness >= LED::getPwmSteps())
{
this->currentBrightness = LED::getPwmSteps();
}
else if (new_cBrightness < 0)
{
this->currentBrightness = 0;
}
else
{
this->currentBrightness = new_cBrightness;
}
//set pin to the new brightness
//std::cout << "new brightness: " << this->currentBrightness << std::endl;
gpioPWM(this->pin, this->currentBrightness);
}
void LED::setTargetBrightness(int new_tBrightness)
{
//new exception for blue, other treatment for blue colored strips as they are
//brighter than other leds
if (new_tBrightness > LED::getPwmSteps())
{
this->targetBrightness = LED::getPwmSteps();
}
else if (new_tBrightness < 0)
{
this->targetBrightness = 0;
}
else
{
this->targetBrightness = new_tBrightness;
}
}
//************************FUNCTIONS*************************************************+
//*********************************general INIT*******************************************
bool LED::initGeneral(void)
{
gpioTerminate(); //shut down all DMA channels and stuff so we can start fresh and easy ;-)
if (gpioInitialise() < 0) //initializes the gpio libary
{
cout << "pigpio initialisation failed." << endl;
return 1;
}
else
{
#ifdef DEBUG
cout << "pigpio initialised okay. initGeneral successful." << endl;
#endif
return 0;
}
}
//************************FADE***************************************************
//fade all leds off. called before terminating the programm
void LED::fadeAllLedsOff(void)
{
for(auto const &iterator : LED::ledMap)
{
iterator.second->setTargetBrightness(0);
iterator.second->fadeInThread();
}
for(auto const &iterator : LED::ledMap)
{
iterator.second->fadeWait();
}
}
//turn all leds off instantly
void LED::turnAllLedsOff(void)
{
for(auto const &iterator : LED::ledMap)
{
iterator.second->setCurrentBrightness(0);
}
}
//***** THREAD EXPLANATION ************************
//for documentation about threads see:
//https://computing.llnl.gov/tutorials/pthreads/
//and about the pthread_create function see:
//https://computing.llnl.gov/tutorials/pthreads/man/pthread_create.txt
//************************************************
//fading in seperate threads allows us to make true simultaneous fading and handling each color individually
//the user can call the fadeCancel function itself, if he want's to start a new fading it is not necessary
//because every fade function checks if theres a fade going on at that moment
void LED::fadeInThread(void)
{
fadeCancel();
this->fading = true;
LED *led = this;
//fadeLauncher: starts and stops thread and so on
int err = pthread_create(&(this->fadeThread), NULL, fadeLauncher, (void *) led);
if(err != 0)
{
std::cerr << "creating fadeThread not possible. errorcode: " << err << std::endl;
exit(1);
}
}
//as pthread_create doesn't support non-static methods we'll need a workaround
//found here: http://stackoverflow.com/questions/1151582/pthread-function-from-a-class
void * LED::fadeLauncher(void *context)
{
//convert the context pointer into a struct pointer to get the fadeTime
//then convert it back into a void pointer
//call fade() and return the value to pthread
void * returnValue = ((LED *)context)->fade();
((LED *)context)->fading = false;
pthread_exit(NULL);
return returnValue;
}
void LED::fadeCancel(void)
{
if(this->fading || this->randomlyFading)
{
pthread_cancel(this->fadeThread);
this->fading = false;
this->randomlyFading = false;
}
}
void LED::fadeWait(void)
{
if (this->randomlyFading == false)
{
int err = pthread_join(this->fadeThread, NULL);
if (err)
{
std::cerr << "error while joining thread. errno: " << err << std::endl;
}
else
{
this->fading = false;
}
}
else
{
//if we're randomly fading we'd have to wait infinitely
this->fadeCancel();
this->randomlyFading = false;
}
}
void * LED::fade(void)
{
//stepsize for the fade
int stepsize = 1;
//calculate the real target brightness it will have (after the trueColorAdjust)
int trueTargetBrightness;
if (trueColorMultiplier > 0 && trueColorMultiplier < 100 && this->targetBrightness > 0)
{
//lower the brightness of the color by a factor (0 = 0%, at 100% [not allowed] there wouldnt be any light)
trueTargetBrightness = this->targetBrightness - ((this->targetBrightness * trueColorMultiplier) / 100);
}
else
{
trueTargetBrightness = this->targetBrightness;
}
std::cout << "true brightness: " << trueTargetBrightness << std::endl;
//calculate the delayUs needed to archieve the specified fadeTime
//steps * delayUs * 1000 = fadeTime [in ms]
//fadeTime is the variable which sets the Time needed to fade
int totalSteps = ((trueTargetBrightness) - (this->currentBrightness));
//we want to have a positive steps number
if (totalSteps < 0)
{
totalSteps = -totalSteps;
}
if (totalSteps > 0)
{
//calculate delay in us
int delayUs = ((LED::fadeTime) * 1000 / (totalSteps)) / stepsize;
//to avoid flickering we'll increase the steosize if the delay is smaller than 6us #
//(as the pwm duty time gets updated every 5us at 200Hz)
while (delayUs <= 15)
{
stepsize++;
delayUs = ((LED::fadeTime) * 1000 / (totalSteps)) / stepsize; //calculate delay in us
}
#ifdef DEBUG
uint32_t startTime = 0; //time to check if there's any overhead
uint32_t endTime = 0; //time to check if there's any overhead
startTime = gpioTick();
#endif
//fading to target brightness
for (int current = this->currentBrightness; current < trueTargetBrightness; current++)
{
//increase currentBRIGHTNESS of that color and write it to the pin
this->setCurrentBrightness(current + stepsize); //we use +1 so it will actually reach the targetBrightness
gpioDelay(delayUs); //make a delay
}
for (int current = this->currentBrightness; current > trueTargetBrightness; current--)
{
//decrease currentBRIGHTNESS of that color and write it to the pin
this->setCurrentBrightness(current - stepsize); //we use -1 so it will actually reach the targetBrightness
gpioDelay(delayUs); //make a delay
}
#ifdef DEBUG
endTime = gpioTick(); //time needed for the fade
printf("time variable for fade: %d \n", LED::fadeTime);
//end-start gives elapsed time in micros; divided by 1000 we have it in millis to compare
cout << "real time needed for fade: " << ((endTime - startTime) / 1000) << endl;
#endif
}
//this->fading = false;
return 0;
}
//****random fade*****
void LED::fadeRandomInThread(void)
{
fadeCancel();
this->fading = true;
this->randomlyFading = true;
LED *led = this;
//fadeLauncher: starts and stops thread and so on
int err = pthread_create(&(this->fadeThread), NULL, fadeRandom, (void *) led);
if(err != 0)
{
std::cerr << "creating fadeRandomThread not possible. errorcode: " << err << std::endl;
exit(1);
}
//delete fadeStruct;
}
//as pthread_create doesn't support non-static methods we'll need a workaround
//found here: http://stackoverflow.com/questions/1151582/pthread-function-from-a-class
void * LED::fadeRandom(void *context)
{
//instead of this-> we'll use ((LED *)context)
((LED *)context)->fading = true;
((LED *)context)->randomlyFading = true;
/* initialize random seed: */
srand (time(NULL));
while (true)
{
//rand % 1000 creates numbers between 0 and 999, ...
//% 1001 should create nubers between 0 and 1000
((LED *)context)->setTargetBrightness(rand() % 1001);
//start fading (fade() is a blocking fade)
((LED *)context)->fade();
}
//INVALID CODE
}
//***************************PINS INIT******************************************************
int LED::initPin(void)
{
int PWMrange = 0; //variable to check the pwm range against the realpwm range
int pwmSteps;
#if PWM_CONFIG
int realRange = 0;
int setRange = 0;
int targetRange = 0;
int targetFrequency = 0;
int frequency = 0;
cout << "enter target frequency :" << endl;
cin >> targetFrequency;
cout << "set frequency to: " << targetFrequency << endl;
frequency = gpioSetPWMfrequency(pin, targetFrequency);
cout << "range was set to closest frequency: " << frequency << endl;
cout << "check frequency: " << gpioGetPWMfrequency(pin) << endl;
cout << "enter target range :" << endl;
cin >> targetRange;
cout << "set range to: " << targetRange << endl;
realRange = gpioSetPWMrange(pin, targetRange);
cout << "range was set to real range: " << realRange << endl;
cout << "check range: " << gpioGetPWMrange(pin) << endl;
#endif
if (gpioSetMode(this->pin, 1)) //set pin to output (1), returns 0 if it went ok
{
cout << "error while setting " << this->pin << " to output" << endl;
return 0;
}
/**************INFOS ABOUT PWM FREQUENCY AND RANGE*******************************
some infos for setting the pwm range of each pin
a sample rate of 5 (default) means that one step can be at least 5us "long"
so if you use a frequency of 200Hz there will be 1000 real steps
Calculations:
1/200s is one cycle = 0,005s which is 5ms (Millis)
1ms equals 1000us (Microseconeds)
so within 5ms there are 1000 5us steps possible
-> if you increase the frequency you have to decrease the range
as far as I understand its realized like that in the pigpio libary:
you set the frequency to whatever you like (w/ SetPWMFrequency)
you set the pwm_range to whatever you like (w/ SetPWMRange)
now you can check the pwmSteps to see how many steps you actually have
(i.e. if you set your frequency to 200Hz and the range to 5000 this will
return 1000 (see calculations above))
BUT if I understand it correctly it uses the range you set (5000 in this example)
so 5000 is the maximum brightness BUT between 0 and 4 there's no real step!
this is the difference between the realRange and the range. In my opinion
it's good if both have the same value (which is true for 200Hz and 1000steps)
********************************************************************************
*/
#ifdef DETAILED_PIN_INIT_INFORMATION
cout << "set " << this->pin << " to output" << endl;
#endif
gpioSetPWMfrequency(this->pin, PWM_FREQUENCY);
#ifdef DETAILED_PIN_INIT_INFORMATION
cout << "check frequency: " << gpioGetPWMfrequency(this->pin) << endl;
#endif
gpioSetPWMrange(this->pin, PWM_RANGE);
pwmSteps = gpioGetPWMrealRange(this->pin);
#ifdef DETAILED_PIN_INIT_INFORMATION
cout << "check real pwm range: " << pwmSteps << endl;
#endif
PWMrange = gpioGetPWMrange(this->pin);
#ifdef DETAILED_PIN_INIT_INFORMATION
cout << "check pwm range: " << PWMrange << endl;
#endif
if (PWMrange != pwmSteps)
{
std::cout << "warning: set pwm range and real pwm range don't match." << std::endl;
std::cout << "pwmrange: " << PWMrange << " pwmSteps: " << pwmSteps << std::endl;
}
gpioPWM(this->pin, 0); //set brightness to 0
//cout << "pwm set to 0 correctly" << endl;
#ifdef DEBUG
cout << "init of pin " << this->pin << " finished successfully." << endl;
#endif
return pwmSteps;
}
LED::LED(std::string led_colorcode, uint16_t led_pin, bool led_isColor, int led_currentBrightness, int led_targetBrightness, int led_trueColorMultiplier)
{
this->colorcode = led_colorcode;
this->pin = led_pin;
this->isColor = led_isColor;
this->currentBrightness = led_currentBrightness;
this->targetBrightness = led_targetBrightness;
this->fading = false;
this->randomlyFading = false;
setTrueColorMultipier(led_trueColorMultiplier);
//initializes each pin. returns 0 if everything went ok
//std::cout << "initializes color \"" << colorcode << "\"" << std::endl;
//pwmSteps is static and should have the same value for every pin
LED::pwmSteps = LED::initPin();
if(LED::pwmSteps == 0) {
//print that there has been an error if this happens (very unlikely)
cout << "error in initPin " << pin;
cout << "which is used by color " << colorcode << endl;
//and exit the program
exit(EXIT_FAILURE);
}
}
LED::~LED(void)
{
//std::cout << "destroy led object" << std::endl;
//this->setCurrentBrightness(0);
}