RSeries astromech firmware
HoloLights.h
Go to the documentation of this file.
1 #ifndef HoloLights_h
2 #define HoloLights_h
3 
4 #include "ReelTwo.h"
5 #include "core/LEDPixelEngine.h"
6 #include "core/SetupEvent.h"
7 #include "core/AnimatedEvent.h"
8 #include "core/CommandEvent.h"
9 #include "core/JawaEvent.h"
10 #include "ServoDispatch.h"
11 
12 #ifdef USE_DEBUG
13 #define HOLO_DEBUG
14 #endif
15 
16 #if USE_LEDLIB == 0
17 template<uint8_t DATA_PIN, uint32_t RGB_ORDER, uint16_t NUM_LEDS>
18 class HoloLEDPCB : public FastLED_NeoPixel<NUM_LEDS, DATA_PIN, RGB_ORDER>
19 {
20 public:
22 };
23 #define USE_HOLO_TEMPLATE 1
24 #elif USE_LEDLIB == 1
25 template<uint8_t DATA_PIN, uint32_t RGB_ORDER, uint16_t NUM_LEDS>
26 class HoloLEDPCB : public Adafruit_NeoPixel
27 {
28 public:
29  HoloLEDPCB() :
30  Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, RGB_ORDER)
31  {
32  }
33 };
34 #else
35  #error Unsupported
36 #endif
37 
55 #if USE_HOLO_TEMPLATE
56 template<uint8_t DATA_PIN, uint32_t RGB_ORDER = GRB, uint16_t NUM_LEDS = 7>
57 class HoloLights :
58  public HoloLEDPCB<DATA_PIN, RGB_ORDER, NUM_LEDS>, SetupEvent, AnimatedEvent, CommandEvent, JawaEvent
59 #else
60 class HoloLights :
61  public Adafruit_NeoPixel, SetupEvent, AnimatedEvent, CommandEvent, JawaEvent
62 #endif
63 {
64 public:
65 #if !USE_HOLO_TEMPLATE
66  enum PixelType
67  {
68  kRGBW = NEO_GRBW + NEO_KHZ800,
69  kRGB = NEO_GRB + NEO_KHZ800
70  };
71 #endif
72  enum HoloID
73  {
77  kRearHolo = 2,
79  kTopHolo = 3,
81  kRadarEye = 4,
84  };
86  {
92  kUp,
107  };
109  {
111  kOff = 0x000000,
113  kRed = 0xFF0000,
115  kOrange = 0xFF8000,
117  kYellow = 0xFFFF00,
119  kGreen = 0x00FF00,
121  kCyan = 0x00FFFF,
123  kBlue = 0x0000FF,
125  kMagenta = 0xFF00FF,
127  kPurple = 0x800080,
129  kWhite = 0xFFFFFF
130  };
131 
132 #if USE_HOLO_TEMPLATE
133 
136  HoloLights(const int id = 0) :
137  fID((id == 0) ? getNextID() : id)
138 #else
142  HoloLights(const byte pin, PixelType type = kRGBW, const int id = 0, const byte numPixels = 7) :
143  Adafruit_NeoPixel(numPixels, pin, type),
144  fID((id == 0) ? getNextID() : id)
145 #endif
146  {
147  setLEDTwitchInterval(45, 180);
149  setHPTwitchInterval(45 + random(15), 120 + random(60));
150 
151  fHPpins[0] = 0;
152  fHPpins[1] = 0;
153 
154  JawaID addr = kJawaOther;
155  switch (fID)
156  {
157  case kFrontHolo:
158  addr = kJawaFrontHolo;
159  break;
160  case kRearHolo:
161  addr = kJawaRearHolo;
162  break;
163  case kTopHolo:
164  addr = kJawaTopHolo;
165  break;
166  case kRadarEye:
167  addr = kJawaRadarEye;
168  break;
169  case kOtherHolo:
170  addr = kJawaOther;
171  break;
172  }
173  setJawaAddress(addr);
174  }
175 
176 #if USE_HOLO_TEMPLATE
177  void begin()
178  {
180  }
181 
182  void show()
183  {
185  }
186 
187  void setBrightness(uint8_t b)
188  {
190  }
191 
192  uint8_t getBrightness()
193  {
195  }
196 
197  uint16_t numPixels()
198  {
200  }
201 
202  void setPixelColor(uint16_t n, uint32_t c)
203  {
205  }
206 #endif
207 
304  virtual void handleCommand(const char* cmd) override
305  {
306  printf("COMMAND: %s\n", cmd);
307  int durationSec = -1;
308  byte typeState = 0;
309  byte functionState = 0;
310  int optionState = -1;
311  int optionState2 = -1;
312 
313  if (*cmd++ != 'H' || *cmd++ != 'P')
314  return;
315 
316  int commandLength = strlen(cmd);
317  const char* pipeIndex = strchr(cmd, '|');
318  if (pipeIndex != NULL)
319  {
320  durationSec = atoi(pipeIndex+1);
321  commandLength = pipeIndex - cmd;
322  }
323  if (cmd[0]=='F' || // Front HP
324  cmd[0]=='R' || // Rear HP
325  cmd[0]=='T' || // Top HP
326  cmd[0]=='X' || // Front & Rear HPs
327  cmd[0]=='Y' || // Front & Top HPs
328  cmd[0]=='Z' || // Rear & Top HPs
329  cmd[0]=='D' || // Radar eye
330  cmd[0]=='O' || // Other HP
331  cmd[0]=='A' ) // All three HP
332  {
333  if (commandLength >= 2)
334  typeState = cmd[1]-'0';
335  if (commandLength >= 4)
336  functionState = (cmd[2]-'0')*10+(cmd[3]-'0');
337 
338  if (commandLength >= 5)
339  {
340  optionState = cmd[4]-'0';
341  }
342  else if (typeState == 1)
343  {
344  optionState = 1; // Set Center as the fallback position
345  }
346  if (commandLength >= 6)
347  {
348  optionState2 = cmd[5]-'0';
349  }
350  // All match A
351  bool match = (cmd[0]=='A');
352  // Front holo matches FXY
353  match = (match || (fID == kFrontHolo && (cmd[0]=='F' || cmd[0]=='X' || cmd[0]=='Y')));
354  // Rear holo matches RXZ
355  match = (match || (fID == kRearHolo && (cmd[0]=='R' || cmd[0]=='X' || cmd[0]=='Z')));
356  // Top holo matches TYZ
357  match = (match || (fID == kTopHolo && (cmd[0]=='T' || cmd[0]=='Y' || cmd[0]=='Z')));
358  // Radar eye matches D
359  match = (match || (fID == kRadarEye && cmd[0]=='D'));
360  // Other holo matches D
361  match = (match || (fID == kOtherHolo && cmd[0]=='O'));
362  if (match)
363  {
364  if (typeState == 0)
365  {
366  flushLEDState(); // Flushes LED Command Arrays
367  fLEDFunction = functionState;
368  if (optionState >= 0)
369  {
370  if (optionState == 0)
371  fLEDOption1 = random(0,9);
372  else
373  fLEDOption1 = optionState;
374  }
375  else
376  {
377  fLEDOption1 = (functionState == 7) ? fShortColor : fDefaultColor;
378  }
379  if (optionState2 >= 0 && functionState == 3)
380  fLEDOption2 = optionState2;
381  else if (optionState2 < 0 && functionState == 3)
382  fLEDOption2 = kDimPulseSpeed;
383  fLEDHalt = (durationSec >= 1) ? durationSec : -1;
384  fLEDHaltTime = millis();
385  varResets();
386  }
387  else if (typeState == 1)
388  {
389  flushHPState(); // Flushes HP Command Array
390  fHPFunction = functionState;
391  fHPOption1 = optionState;
392  if (durationSec >= 1)
393  fHPHalt = durationSec;
394 
395  fHPHaltTime = millis();
396  fWagCount = -1;
397  }
398  }
399  }
400  else if (cmd[0] == 'S') // Major Sequences (Both LEDS and HP Servos)
401  {
402  if (commandLength >= 2)
403  {
404  functionState = (cmd[1]-'0');
405  selectSequence(functionState, durationSec);
406  }
407  }
408  }
409 
410  virtual void jawaCommand(char cmd, int arg, int value) override
411  {
412  }
413 
417  virtual void animate() override
418  {
419  if (fLEDHalt != -1)
420  {
421  if (fLEDHaltTime + (fLEDHalt * 1000L) < millis())
422  {
423  flushLEDState();
424  off(); // Clears Any Remaining Lit LEDs
425  resetLEDTwitch();
426  }
427  }
428  switch (fLEDFunction)
429  {
430  case 1:
431  effectColorProjectorLED(5); // Leia Sequence (Blue)
432  break;
433  case 2:
434  effectColorProjectorLED(fLEDOption1);
435  break;
436  case 3:
437  effectDimPulse(fLEDOption1, fLEDOption2);
438  break;
439  case 4:
440  effectCycle(fLEDOption1);
441  break;
442  case 5:
443  setColor(fLEDOption1);
444  break;
445  case 6:
446  effectRainbow();
447  break;
448  case 7:
449  effectShortCircuit(fLEDOption1);
450  break;
451  case 96:
452  // Clear Function, Disable Random LED Twitch, enable off color override, and random sequences (if enabled)
453  fEnableTwitchLED = 0;
454  resetLEDTwitch();
455  fOffColorOverride = true;
456  flushLEDState();
457  break;
458  case 97:
459  // Clear Function, Enable Random LED Twitch using random LED sequences, enable off color override.
460  if (fLEDOption1 == 1 || fLEDOption1 == 2)
461  {
462  fEnableTwitchLED = fLEDOption1;
463  }
464  else
465  {
466  fEnableTwitchLED = fStartEnableTwitchLED;
467  }
468  resetLEDTwitch();
469  fOffColorOverride = true;
470  flushLEDState();
471  break;
472  case 98:
473  // Clear Function, Disable Random LED Twitch, random sequences (if enabled) and disable off color override,
474  fEnableTwitchLED = 0;
475  resetLEDTwitch();
476  fOffColorOverride = false;
477  flushLEDState();
478  break;
479  case 99:
480  // Clear Function, Enable Random LED Twitch, using random LED sequences, disable off color override,
481  if (fLEDOption1 == 1 || fLEDOption1 == 2)
482  {
483  fEnableTwitchLED = fLEDOption1;
484  }
485  else
486  {
487  fEnableTwitchLED = fStartEnableTwitchLED;
488  }
489  resetLEDTwitch();
490  fOffColorOverride = false;
491  flushLEDState();
492  break;
493  case 100:
494  setColor(fLEDOption1);
495  break;
496  default:
497  break;
498  }
499  if (fHPHalt > 0)
500  {
501  if (millis() - fHPHaltTime >= (unsigned(fHPHalt) * 1000L))
502  {
503  flushHPState();
504  fWagCount = -1;
505  }
506  }
507  switch (fHPFunction)
508  {
509  case 1:
510  moveHP(fHPOption1, SERVO_SPEED[0]);
511  flushHPState();
512  break;
513  case 2:
514  //RCHP(1);
515  break;
516  case 3:
517  //RCHP(2);
518  break;
519  case 4:
520  twitchHP(0);
521  flushHPState();
522  break;
523  case 5:
524  // Wags HP Left/Right
525  wagHP(1);
526  break;
527  case 6:
528  // Wags HP Up/Down
529  wagHP(2);
530  break;
531  case 98:
532  // Clear Function, Disable Servo Random Twitch
533  fEnableTwitchHP = false;
534  flushHPState();
535  break;
536  case 99:
537  // Clear Function, Enable Servo Random Twitch
538  fEnableTwitchHP = true;
539  flushHPState();
540  break;
541  default:
542  break;
543  }
544  if (millis() > fTwitchLEDTime && fEnableTwitchLED >= 1 && fLEDFunction > 99)
545  {
546  fTwitchLEDTime = (1000L * random(fLEDTwitchInterval[0], fLEDTwitchInterval[1])) + millis();
547  fTwitchLEDRunTime = random(fLEDTwitchRunInterval[0], fLEDTwitchRunInterval[1]);
548  flushLEDState();
549  fLEDHaltTime = millis();
550  varResets();
551  if (fEnableTwitchLED == 2)
552  {
553  fLEDFunction = random(2,7);
554  fLEDOption1 = random(1,9);
555  fLEDOption2 = random(1,9);
556  fLEDHalt = fTwitchLEDRunTime;
557  }
558  else
559  {
560  fLEDFunction = fDefaultLEDTwitchCommand[0];
561  fLEDOption1 = fDefaultLEDTwitchCommand[1];
562  fLEDOption2 = fDefaultLEDTwitchCommand[2];
563  fLEDHalt = fTwitchLEDRunTime;
564  }
565  }
566  if (millis() > fTwitchHPTime && fEnableTwitchHP && fHPFunction > 99)
567  {
568  twitchHP(1);
569  resetHPTwitch();
570  }
571  if (fDirty)
572  {
574  show();
576  fDirty = false;
577  }
578  }
579 
583  virtual void selectSequence(int sequence, int durationSec)
584  {
585  switch (sequence)
586  {
587  case 1:
588  varResets(); // Resets the Variables for LEDs
589  flushLEDState(); // Flushes LED Command Arrays
590  fHPFunction = 0; // Set HP to Do Nothing
591  fLEDFunction = 0; // Set LED to Do Nothing
592  if (fID == kFrontHolo)
593  {
594  moveHP(kDown, SERVO_SPEED[0]); // Moves Front HP to Down Position
595  fLEDFunction = 1; // Set Leia LED Sequence to run each loop.
596  }
597  if (durationSec >= 1)
598  {
599  fLEDHalt = durationSec; // Set LED Halt timeout if passed via command.
600  fLEDHaltTime = millis(); // and note start time
601  fHPHalt = durationSec; // Set HP Halt timeout if passed via command.
602  fHPHaltTime = millis(); // and note start time
603  }
604  break;
605  case 7:
606  fEnableTwitchHP = false; // Disables Auto HP Twith
607  flushLEDState(); // Flushes LED Command Array
608  flushHPState(); // Flushes HP Command Array
609  off(); // Turns Off LEDs
610  fEnableTwitchLED = 0; // Disables Auto LED Twith
611  break;
612  case 8:
613  fEnableTwitchHP = true; // Enables Auto HP Twith
614  flushLEDState(); // Flushes LED Command Array
615  flushHPState(); // Flushes HP Command Array
616  off(); // Turns Off LEDs
617  fEnableTwitchLED = 1; // Enables Auto LED Twith
618  break;
619  case 9:
620  fEnableTwitchHP = true; // Enables Auto HP Twith on all HPs
621  flushLEDState(); // Flushes LED Command Array
622  flushHPState(); // Flushes HP Command Array
623  off(); // Turns Off LEDs
624  fEnableTwitchLED = 2; // Enables Auto LED Twith on all HPs using random sequences
625  break;
626  default:
627  break;
628  }
629  }
630 
634  void assignServos(ServoDispatch* dispatcher, byte hServo, byte vServo)
635  {
636  fServoDispatch = dispatcher;
637 
638  fHPpins[0] = hServo;
639  fHPpins[1] = vServo;
640  }
641 
645  inline int getID()
646  {
647  return fID;
648  }
649 
653  virtual void setup() override
654  {
656 
657  setBrightness(BRIGHT);
658  dirty();
659 
660  moveHP(kCenter);
661  }
662 
666  inline void brighter()
667  {
669  }
670 
674  inline void dimmer()
675  {
677  }
678 
682  void off()
683  {
684  uint16_t numLEDs = numPixels();
685  for (unsigned i = 0; i < numLEDs; i++)
686  setPixelColor(i, kOff);
687  dirty();
688  }
689 
704  void setColor(int c)
705  {
706  uint16_t numLEDs = numPixels();
707  for (unsigned i = 0; i < numLEDs; i++)
708  {
709  setPixelColor(i, basicColor(c));
710  }
711  dirty();
712  }
713 
715  {
716  off();
717  fTwitchLEDTime = (1000L * random(fLEDTwitchInterval[0], fLEDTwitchInterval[1])) + millis();
718  }
719 
721  {
722  fTwitchHPTime = (1000 * random(fHPTwitchInterval[0], fHPTwitchInterval[1])) + millis();
723  }
724 
725  void setHoloPosition(float hpos, float vpos, int speed = 0)
726  {
727  if (fServoDispatch != NULL)
728  {
729  fServoDispatch->moveTo(fHPpins[0], speed, hpos);
730  fServoDispatch->moveTo(fHPpins[1], speed, vpos);
731  }
732  }
733 
737  void moveHP(byte pos, int speed = 0)
738  {
739  if (fServoDispatch == NULL || pos >= kNumPositions)
740  return;
741 
742  static const float sPositions[kNumPositions][2] PROGMEM =
743  {
744  // Down
745  { 0.5, 1.0 },
746 
747  // Center
748  { 0.5, 0.5 },
749 
750  // Up
751  { 0.5, 0.0 },
752 
753  // Left
754  { 1.0, 0.5 },
755 
756  // Upper Left
757  { 1.0, 0.0 },
758 
759  // Lower Left
760  { 1.0, 1.0 },
761 
762  // Right
763  { 0.0, 0.5 },
764 
765  // Upper Right
766  { 0.0, 0.0 },
767 
768  // Lower Right
769  { 0.0, 1.0 }
770  };
771  setHoloPosition(pgm_read_float(&sPositions[pos][0]), pgm_read_float(&sPositions[pos][1]), speed);
772  #ifdef HOLO_DEBUG
773  static const char* position[] = {
774  "Down",
775  "Center",
776  "Up",
777  "Left",
778  "Upper Left",
779  "Lower Left",
780  "Right",
781  "Upper Right",
782  "lower Right"
783  };
784  DEBUG_PRINT(F("Holo#"));
785  DEBUG_PRINT(getID());
786  DEBUG_PRINT(F(" moved to the "));
787  DEBUG_PRINT(position[pos]);
788  DEBUG_PRINTLN(F(" position."));
789  #endif
790  }
791 
792  void twitchHP(byte randtwitch)
793  {
794  UNUSED_ARG(randtwitch)
795  int speed = random(SERVO_SPEED[0], SERVO_SPEED[1]);
796  #ifdef HOLO_DEBUG
797  if (randtwitch == 1)
798  {
799  DEBUG_PRINT(F("Random Holo#"));
800  DEBUG_PRINT(getID());
801  DEBUG_PRINTLN(F(" HP twitch triggered...."));
802  }
803  #endif
804  moveHP(random(0, kNumPositions), speed);
805  }
806 
807  void wagHP(byte type)
808  {
809  int speed = 250;
810  if (fWagCount < 0)
811  {
812  fWagCount = 0;
813  fWagTimer = millis();
814  }
815  if (millis() - fWagTimer >= 400)
816  {
817  fWagCount++;
818  fWagTimer = millis();
819  if (type == 1)
820  {
821  // On Odd Count, Wag HP Left
822  // On Even Count, Wag HP Right
823  moveHP((fWagCount % 2) ? 3 : 6 , speed);
824  }
825  if (type == 2)
826  {
827  // On Odd Count, Wag HP Down
828  // On Even Count, Wag HP Up
829  moveHP((fWagCount % 2) ? 0 : 2, speed);
830  }
831  }
832  }
834  void effectColorProjectorLED(int c)
835  {
836  uint16_t numLEDs = numPixels();
837  if ((millis() - fCounter) > fInterval)
838  {
839  for (unsigned i = 0; i < numLEDs; i++)
840  {
841  setPixelColor(i, basicColor(c, random(0,10)));
842  }
843  dirty();
844  fCounter = millis();
845  fInterval = random(50,150);
846  }
847  }
848 
850  void effectDimPulse(int c, int setting)
851  {
852  uint16_t numLEDs = numPixels();
853  unsigned inter = map(setting, 0, 9, dimPulseSpeedRange[1], dimPulseSpeedRange[0]);
854  if ((millis() - fCounter) > fInterval)
855  {
856  unsigned elapsed = millis() - fCounter;
857  int frames = elapsed / inter;
858  if (frames >= 64)
859  {
860  fCounter = millis();
861  }
862  if (frames > 32)
863  {
864  frames = 32 - (frames - 32);
865  }
866  if (elapsed >= inter)
867  {
868  for (unsigned i = 0; i < numLEDs; i++)
869  setPixelColor(i, dimColorVal(c, (frames * 8)));
870  dirty();
871  }
872  }
873  }
874 
876  void effectShortCircuit(int c)
877  {
878  uint16_t numLEDs = numPixels();
879  const int kShortCircuitMaxLoops = 20;
880  if (fSCloop <= kShortCircuitMaxLoops)
881  {
882  if ((millis() - fCounter) > fSCinterval)
883  {
884  if (fSCflag == false)
885  {
886  for (unsigned i = 0; i < numLEDs; i++)
887  setPixelColor(i, kOff);
888  fSCflag = true;
889  fSCinterval = 10 + (fSCloop * random(15,25));
890  }
891  else
892  {
893  for (unsigned i = 0; i < numLEDs; i++)
894  setPixelColor(i, basicColor(c, random(0,10)));
895  fSCflag = false;
896  fSCloop++;
897  }
898  fCounter = millis();
899  dirty();
900  }
901  }
902  }
903 
905  void effectCycle(int c)
906  {
907  uint16_t numLEDs = numPixels();
908  const unsigned int inter = 75;
909  if ((millis() - fCounter) > inter)
910  {
911  fCounter = millis();
912  if (numLEDs == 7)
913  {
914  /* 7 pixels with one center */
915  setPixelColor(0, kOff); // Center LED is always off
916  if (fFrame >= numLEDs)
917  {
918  fFrame = 0;
919  }
920  for (unsigned i = 1; i < numLEDs; i++)
921  {
922  if (i == fFrame)
923  {
924  setPixelColor(i, basicColor(c));
925  }
926  else
927  {
928  setPixelColor(i, kOff);
929  }
930  }
931  }
932  else
933  {
934  /* More than 7 pixels no center */
935  if (fFrame >= numLEDs)
936  {
937  fFrame = 0;
938  }
939  for (unsigned i = 0; i < numLEDs; i++)
940  {
941  if (i == fFrame)
942  {
943  setPixelColor(i, basicColor(c));
944  }
945  else
946  {
947  setPixelColor(i, kOff);
948  }
949  }
950  }
951  dirty();
952  fFrame++;
953  }
954  }
955 
957  void effectRainbow()
958  {
959  uint16_t numLEDs = numPixels();
960  const unsigned int inter = 10;
961  unsigned elapsed = millis() - fCounter;
962  unsigned int frames = elapsed / inter;
963  if (frames > 256 * 5)
964  {
965  fCounter = millis();
966  }
967  else
968  {
969  for (unsigned i = 0; i < numLEDs; i++)
970  {
971  setPixelColor(i, getWheelColor(((i * 256 / numLEDs) + frames) & 255));
972  }
973  if (elapsed >= inter)
974  {
975  dirty();
976  }
977  }
978  }
979 
980  void setLEDTwitchInterval(unsigned minSeconds, unsigned maxSeconds)
981  {
982  if (minSeconds < maxSeconds)
983  {
984  fLEDTwitchInterval[0] = minSeconds;
985  fLEDTwitchInterval[1] = maxSeconds;
986  fTwitchLEDTime = (1000L * random(fLEDTwitchInterval[0], fLEDTwitchInterval[1])) + millis();
987  }
988  }
989 
990  void setLEDTwitchRunInterval(unsigned minSeconds, unsigned maxSeconds)
991  {
992  if (minSeconds < maxSeconds)
993  {
994  fLEDTwitchRunInterval[0] = minSeconds;
995  fLEDTwitchRunInterval[1] = maxSeconds;
996  fTwitchLEDRunTime = (1000L * random(fLEDTwitchRunInterval[0], fLEDTwitchRunInterval[1])); // Randomly sets initial LED Twitch Run Time value
997  }
998  }
999 
1000  void setHPTwitchInterval(unsigned minSeconds, unsigned maxSeconds)
1001  {
1002  if (minSeconds < maxSeconds)
1003  {
1004  fHPTwitchInterval[0] = minSeconds;
1005  fHPTwitchInterval[1] = maxSeconds;
1006  resetHPTwitch();
1007  }
1008  }
1009 
1010  inline void dirty()
1011  {
1012  fDirty = true;
1013  }
1014 
1015 #if USE_LEDLIB == 2
1016  inline void begin() { Begin(); }
1017  inline void show() { Show(); }
1018  inline void setBrightness(uint8_t b) { SetBrightness(b); }
1019  inline uint8_t getBrightness() { return GetBrightness(); }
1020  inline uint16_t numPixels() { return PixelCount(); }
1021  inline void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b)
1022  {
1023  SetPixelColor(n, RgbColor(r, g, b));
1024  }
1025  inline void setPixelColor(uint16_t n, uint32_t c)
1026  {
1027  SetPixelColor(n, RgbColor((c>>16)&0xFF, (c>>8)&0xFF, c&0xFF));
1028  }
1029 #endif
1030 
1031 private:
1032  enum
1033  {
1034  BRIGHT = 100
1035  };
1036 
1037  void flushLEDState()
1038  {
1039  int color = -1;
1040  if (fOffColor >= 0 && !fOffColorOverride)
1041  {
1042  fLEDFunction = 100;
1043  color = fOffColor;
1044  }
1045  else
1046  {
1047  fLEDFunction = -1;
1048  }
1049  fLEDOption1 = color;
1050  fLEDOption2 = -1;
1051  fLEDHalt = -1;
1052  }
1053 
1054  void flushHPState()
1055  {
1056  fHPFunction = -1;
1057  fHPOption1 = -1;
1058  fHPHalt = -1;
1059  if (fEnableTwitchHP)
1060  {
1061  // Resets HP Twitch time so random twich doesn't immediately occur following external position command.
1062  resetHPTwitch();
1063  }
1064  }
1065 
1066  void varResets()
1067  {
1068  fFrame = 0;
1069  fSCflag = false;
1070  fSCloop = 0;
1071  fSCinterval = 10;
1072  fInterval = 100;
1073  off();
1074  }
1075 
1076  static inline uint32_t basicColor(int color, int variant = 0)
1077  {
1078  static const uint32_t basicColors[10][10] PROGMEM =
1079  {{ kRed, kYellow, kGreen, kCyan, kBlue, kMagenta, kPurple, kWhite, kOff, kOff}, // Random
1080  { kRed, kRed, kRed, kWhite, 0xFFA0A0, 0xFD5555, 0xFFD3D3, kOff, kOff, kOff}, // Red
1081  { kYellow, kYellow, kYellow, kWhite, 0xFDFD43, 0xFFFF82, 0xFFFFBA, kOff, kOff, kOff}, // Yellow
1082  { kGreen, kGreen, kGreen, kWhite, 0x57FC57, 0x80FC80, 0xBDFFB1, kOff, kOff, kOff}, // Green
1083  { kCyan, kCyan, kCyan, kWhite, 0x38FFFF, 0x71FDFD, 0xA4FDFD, kOff, kOff, kOff}, // Cyan
1084  { kBlue, kBlue, kBlue, kWhite, 0xACACFF, 0x7676FF, 0x5A5AFF, kOff, kOff, kOff}, // Blue
1085  { kMagenta, kMagenta, kMagenta, kWhite, 0xFB3BFB, 0xFD75FD, 0xFD9EFD, kOff, kOff, kOff}, // Magenta
1086  { kOrange, kOrange, kOrange, kWhite, 0xFB9B3A, 0xFFBE7D, 0xFCD2A7, kOff, kOff, kOff}, // Orange
1087  { kPurple, kPurple, kPurple, kWhite, 0xA131A1, 0x9B449B, 0xBD5FBD, kOff, kOff, kOff}, // Purple
1088  { kWhite, kWhite, kWhite, kWhite, 0xB7B6B6, 0x858484, 0xA09F9F, kOff, kOff, kOff}}; // White
1089  return pgm_read_dword(&basicColors[color][variant]);
1090  }
1091 
1092  static int getNextID()
1093  {
1094  static int sID;
1095  return ++sID;
1096  }
1097 
1104 
1105  static inline uint32_t RGB(byte r, byte g, byte b)
1106  {
1107  return (uint32_t(r)<<16) | (uint32_t(g)<<8) | (uint32_t(b));
1108  }
1109 
1116 
1117  static uint32_t getWheelColor(byte wheelPos)
1118  {
1119  if (wheelPos < 85)
1120  {
1121  return RGB(wheelPos * 3, 255 - wheelPos * 3, 0);
1122  }
1123  else if (wheelPos < 170)
1124  {
1125  wheelPos -= 85;
1126  return RGB(255 - wheelPos * 3, 0, wheelPos * 3);
1127  }
1128  wheelPos -= 170;
1129  return RGB(0, wheelPos * 3, 255 - wheelPos * 3);
1130  }
1131 
1141 
1142  static uint32_t dimColorVal(int c, int brightness)
1143  {
1144  if (brightness)
1145  {
1146  switch (c)
1147  {
1148  case 1:
1149  return RGB(255 / brightness, 0, 0);
1150  case 2:
1151  return RGB(255 / brightness, 255 / brightness, 0);
1152  case 3:
1153  return RGB(0, 255 / brightness, 0);
1154  case 4:
1155  return RGB(0, 255 / brightness, 255 / brightness);
1156  case 5:
1157  return RGB(0, 0, 255 / brightness);
1158  case 6:
1159  return RGB(255 / brightness, 0, 255 / brightness);
1160  case 7:
1161  return RGB(255 / brightness, 180 / brightness, 0);
1162  case 8:
1163  return RGB(255 / brightness, 255 / brightness, 255 / brightness);
1164  case 9:
1165  return kOff;
1166  }
1167  }
1168  return kOff;
1169  }
1170 
1172 
1173  int fID;
1174 
1175  // General counters and timers shared across more than one animation
1176  unsigned long fCounter = 0;
1177  unsigned int fInterval = 100;
1178 
1179  unsigned int fLEDTwitchInterval[2];
1180  unsigned int fLEDTwitchRunInterval[2];
1181 
1182  unsigned int fHPTwitchInterval[2];
1183 
1184  // Short Circuit Animation
1185  byte fSCloop = 0;
1186  bool fSCflag = false;
1187  bool fDirty = false;
1188  unsigned int fSCinterval = 10;
1189 
1190  // Cycle Animation
1191  byte fFrame = 0;
1192 
1193  // Wag Animation
1194  int fWagCount = -1;
1195  unsigned long fWagTimer = 0;
1196 
1197  unsigned long fTwitchLEDTime = 3800 + random(10) * 100;
1198  unsigned long fTwitchLEDRunTime;
1199 
1200  unsigned long fTwitchHPTime = 4000; //HPs Start 4 seconds after boot;
1201 
1202  unsigned long fLEDHaltTime = 0;
1203  unsigned long fHPHaltTime = 0;
1204 
1205  bool fStartEnableTwitchLED = true;
1206  bool fEnableTwitchHP;
1207  byte fEnableTwitchLED = 1;
1208 
1209  int fOffColor = -1;
1210  bool fOffColorOverride = false;
1211 
1212  byte fLEDFunction = -1;
1213  byte fLEDOption1 = -1;
1214  byte fLEDOption2 = -1;
1215  int fLEDHalt = -1;
1216 
1217  // HP: Sequence, Color, Speed
1218  byte fDefaultLEDTwitchCommand[3] = { 1, 5, 0 };
1219 
1220  byte fHPFunction = -1;
1221  byte fHPOption1 = -1;
1222  int fHPHalt = -1;
1223 
1224  byte fHPpins[2];
1225  ServoDispatch* fServoDispatch = NULL;
1226 
1246  uint8_t fDefaultColor = 5; // Blue, Color integer value for the hue of default sequence.
1247  uint8_t fShortColor = 7; // Orange, Color integer value for the hue of ShortCircuit Message.
1248 
1249  const unsigned int SERVO_SPEED[2] = {150, 400};
1250 
1251  const int kDimPulseSpeed = 5;
1252  const uint8_t dimPulseSpeedRange[2] = {5, 75}; // Range used to map to value options 0-9, Lower is faster.
1253 };
1254 
1255 #if USE_HOLO_TEMPLATE
1256 template<uint8_t DATA_PIN = 45, uint32_t RGB_ORDER = GRB, uint16_t NUM_LEDS = 12>
1257 class HoloOLED :
1258  public HoloLights<DATA_PIN, RGB_ORDER, NUM_LEDS>
1259 #else
1260 class HoloOLED :
1261  public HoloLights
1262 #endif
1263 {
1264 public:
1265 #if USE_HOLO_TEMPLATE
1266 
1269  HoloOLED(HardwareSerial& oledSerialPort, const int id = 0, const byte resetPin = 46) :
1270  HoloLights<DATA_PIN, RGB_ORDER, NUM_LEDS>(id),
1271 #else
1275  HoloOLED(HardwareSerial& oledSerialPort, PixelType type = kRGBW, const int id = 0, const byte pin = 45, const byte resetPin = 46, const byte numPixels = 12) :
1276  HoloLights(pin, type, id, numPixels),
1277 #endif
1278  fSerialInit(oledSerialPort),
1279  fSerialPort(oledSerialPort),
1280  fResetPin(resetPin),
1281  fMovieIndex(-1),
1282  fResetState(false)
1283  {
1284  }
1285 
1289  virtual void setup() override
1290  {
1291  #if USE_HOLO_TEMPLATE
1293  #else
1295  #endif
1296  pinMode(fResetPin, OUTPUT);
1297  }
1298 
1302  virtual void handleCommand(const char* cmd) override
1303  {
1304  if (cmd[0] != 'H' || cmd[1] != 'O')
1305  {
1306  #if USE_HOLO_TEMPLATE
1308  #else
1310  #endif
1311  return;
1312  }
1313  }
1314 
1315  bool isPlaying()
1316  {
1317  return (fMovieIndex >= 0 || (fMovieIndex == -1 && !fResetState && fNextCmd > millis()));
1318  }
1319 
1320  virtual void animate()
1321  {
1322  #if USE_HOLO_TEMPLATE
1324  #else
1326  #endif
1327  if (fResetState)
1328  {
1329  if (fNextCmd < millis())
1330  {
1331  digitalWrite(fResetPin, HIGH);
1332  fResetState = false;
1333  fNextCmd = millis() + 10000;
1334  }
1335  }
1336  else if (fMovieIndex == 0)
1337  {
1338  DEBUG_PRINT("STOP MOVIE: "); DEBUG_PRINTLN(fMovieIndex);
1339  fSerialPort.print((char)(fMovieIndex));
1340  fSerialPort.flush();
1341  fNextCmd = millis();
1342  fMovieIndex = -1;
1343  }
1344  else if (fMovieIndex > 0)
1345  {
1346  DEBUG_PRINT("PLAY MOVIE: "); DEBUG_PRINTLN(fMovieIndex);
1347  fSerialPort.print((char)(fMovieIndex));
1348  fSerialPort.flush();
1349  fNextCmd = millis() + 20000;
1350  fMovieIndex = -1;
1351  }
1352  }
1353 
1354  void reset()
1355  {
1356  digitalWrite(fResetPin, LOW);
1357  fNextCmd = millis() + 100;
1358  fResetState = true;
1359  fMovieIndex = -1;
1360  }
1361 
1362  void playMovie(byte movieIndex)
1363  {
1364  // if (isPlaying())
1365  // reset();
1366  // else
1367  // fNextCmd = 0;
1368  fMovieIndex = movieIndex;
1369  }
1370 
1371  void stopMovie()
1372  {
1373  playMovie(0);
1374  }
1375 
1376 private:
1377  class SerialInit
1378  {
1379  public:
1380  SerialInit(HardwareSerial& port)
1381  {
1382  // 9600 is the default baud rate for 4D Systems uOLED-96-G2 display.
1383  port.begin(9600);
1384  }
1385  };
1386 
1387  SerialInit fSerialInit;
1388  Stream& fSerialPort;
1389  byte fResetPin;
1390  int fMovieIndex;
1391  bool fResetState;
1392  uint32_t fNextCmd;
1393 };
1394 
1395 #endif
LEDPixelEngine.h
HoloLights::twitchHP
void twitchHP(byte randtwitch)
Definition: HoloLights.h:792
TEENSY_PROP_NEOPIXEL_SETUP
#define TEENSY_PROP_NEOPIXEL_SETUP()
Definition: ReelTwo.h:163
ServoDispatch.h
HoloLights::kOrange
@ kOrange
Orange.
Definition: HoloLights.h:115
HoloLEDPCB
Definition: HoloLights.h:18
kJawaFrontHolo
@ kJawaFrontHolo
Definition: JawaEvent.h:14
kJawaOther
@ kJawaOther
Definition: JawaEvent.h:17
JawaID
JawaID
Definition: JawaEvent.h:6
HoloLights::kYellow
@ kYellow
Yellow.
Definition: HoloLights.h:117
HoloLights::kOtherHolo
@ kOtherHolo
Other holoprojector ID.
Definition: HoloLights.h:83
HoloLights::kBlue
@ kBlue
Blue.
Definition: HoloLights.h:123
HoloLights::resetHPTwitch
void resetHPTwitch()
Definition: HoloLights.h:720
CommandEvent
Base class for all command enabled devices. CommandEvent::handleCommand() is called for each device e...
Definition: CommandEvent.h:17
HoloLights::kDown
@ kDown
Holoprojector position down.
Definition: HoloLights.h:88
HoloLights::getID
int getID()
Definition: HoloLights.h:645
DEBUG_PRINT
#define DEBUG_PRINT(s)
Definition: ReelTwo.h:189
ReelTwo.h
SetupEvent.h
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
HoloLights::brighter
void brighter()
Increase the brightness of the holoprojector.
Definition: HoloLights.h:666
SetupEvent
Base class for all devices that require setup that cannot happen in the constructor....
Definition: SetupEvent.h:15
HoloOLED::isPlaying
bool isPlaying()
Definition: HoloLights.h:1315
HoloLights::kGreen
@ kGreen
Green.
Definition: HoloLights.h:119
AnimatedEvent.h
HoloLights::HoloLights
HoloLights(const int id=0)
Constructor.
Definition: HoloLights.h:136
HoloLights< 45, GRB, 12 >::HoloPosition
HoloPosition
Definition: HoloLights.h:85
HoloLights::kRearHolo
@ kRearHolo
Rear holoprojector ID.
Definition: HoloLights.h:77
HoloOLED::stopMovie
void stopMovie()
Definition: HoloLights.h:1371
HoloLights::setHPTwitchInterval
void setHPTwitchInterval(unsigned minSeconds, unsigned maxSeconds)
Definition: HoloLights.h:1000
DEBUG_PRINTLN
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:188
HoloLights::kWhite
@ kWhite
White.
Definition: HoloLights.h:129
HoloLights
Controls the movement and display functions of a single Holoprojector.
Definition: HoloLights.h:57
HoloLights::getBrightness
uint8_t getBrightness()
Definition: HoloLights.h:192
HoloLights::kUpperLeft
@ kUpperLeft
Holoprojector position upper left.
Definition: HoloLights.h:96
HoloLights::kRight
@ kRight
Holoprojector position right.
Definition: HoloLights.h:100
HoloLights::kMagenta
@ kMagenta
Magenta.
Definition: HoloLights.h:125
TEENSY_PROP_NEOPIXEL_BEGIN
#define TEENSY_PROP_NEOPIXEL_BEGIN()
Definition: ReelTwo.h:166
HoloLights::kRed
@ kRed
Red.
Definition: HoloLights.h:113
HoloOLED
Definition: HoloLights.h:1257
HoloLights::kNumPositions
@ kNumPositions
Total count.
Definition: HoloLights.h:106
HoloLights::kUpperRight
@ kUpperRight
Holoprojector position upper right.
Definition: HoloLights.h:102
HoloLights::kTopHolo
@ kTopHolo
Top holoprojector ID.
Definition: HoloLights.h:79
ServoDispatch::moveTo
void moveTo(uint16_t num, uint32_t startDelay, uint32_t moveTime, float pos)
Definition: ServoDispatch.h:132
HoloLights::off
void off()
Turn of all LEDs.
Definition: HoloLights.h:682
HoloOLED::reset
void reset()
Definition: HoloLights.h:1354
HoloLights::jawaCommand
virtual void jawaCommand(char cmd, int arg, int value) override
Subclasses should override this method to handle commands specifying a value.
Definition: HoloLights.h:410
HoloLights::dimmer
void dimmer()
Decrease the brightness of the holoprojector.
Definition: HoloLights.h:674
HoloLights::kPurple
@ kPurple
Purple.
Definition: HoloLights.h:127
HoloLights::kOff
@ kOff
Off.
Definition: HoloLights.h:111
HoloLights::setPixelColor
void setPixelColor(uint16_t n, uint32_t c)
Definition: HoloLights.h:202
HoloLights::kFrontHolo
@ kFrontHolo
Front holoprojector ID.
Definition: HoloLights.h:75
HoloLights::begin
void begin()
Definition: HoloLights.h:177
HoloOLED::playMovie
void playMovie(byte movieIndex)
Definition: HoloLights.h:1362
HoloLights::kRadarEye
@ kRadarEye
Other holoprojector ID.
Definition: HoloLights.h:81
JawaEvent
Base class for all devices implementing JAWA lite support.
Definition: JawaEvent.h:31
HoloLights::setColor
void setColor(int c)
Set projector to a solid color.
Definition: HoloLights.h:704
JawaEvent::setJawaAddress
void setJawaAddress(int addr)
Specify the JAWA address of this device.
Definition: JawaEvent.h:84
HoloOLED::animate
virtual void animate()
Runs through one frame of animation for this holoprojector instance.
Definition: HoloLights.h:1320
kJawaTopHolo
@ kJawaTopHolo
Definition: JawaEvent.h:16
kJawaRadarEye
@ kJawaRadarEye
Definition: JawaEvent.h:18
HoloLights::assignServos
void assignServos(ServoDispatch *dispatcher, byte hServo, byte vServo)
Assign ServoDispatcher and servos for horizontal and vertical movement.
Definition: HoloLights.h:634
HoloLights::kCenter
@ kCenter
Holoprojector position center.
Definition: HoloLights.h:90
HoloLights::setLEDTwitchRunInterval
void setLEDTwitchRunInterval(unsigned minSeconds, unsigned maxSeconds)
Definition: HoloLights.h:990
HoloLights::dirty
void dirty()
Definition: HoloLights.h:1010
HoloLights::kLeft
@ kLeft
Holoprojector position left.
Definition: HoloLights.h:94
JawaEvent.h
HoloLights::numPixels
uint16_t numPixels()
Definition: HoloLights.h:197
HoloLights::setup
virtual void setup() override
Configures the NeoPixel ring and centers the holoprojector if servos have been assigned.
Definition: HoloLights.h:653
HoloLights::moveHP
void moveHP(byte pos, int speed=0)
Move holoprojector to the specified position.
Definition: HoloLights.h:737
HoloLights::kCyan
@ kCyan
Cyan.
Definition: HoloLights.h:121
ServoDispatch
Servo interace implemented eitehr by ServoDispatchPCA9685 or ServoDispatchDirect.
Definition: ServoDispatch.h:83
HoloLights< 45, GRB, 12 >::HoloID
HoloID
Definition: HoloLights.h:72
kJawaRearHolo
@ kJawaRearHolo
Definition: JawaEvent.h:15
HoloLights< 45, GRB, 12 >::HoloColors
HoloColors
Definition: HoloLights.h:108
HoloLights::selectSequence
virtual void selectSequence(int sequence, int durationSec)
Specify the sequence to animate.
Definition: HoloLights.h:583
HoloLights::resetLEDTwitch
void resetLEDTwitch()
Definition: HoloLights.h:714
HoloOLED::HoloOLED
HoloOLED(HardwareSerial &oledSerialPort, const int id=0, const byte resetPin=46)
Constructor.
Definition: HoloLights.h:1269
HoloLights::setBrightness
void setBrightness(uint8_t b)
Definition: HoloLights.h:187
HoloLights::show
void show()
Definition: HoloLights.h:182
HoloLights::setLEDTwitchInterval
void setLEDTwitchInterval(unsigned minSeconds, unsigned maxSeconds)
Definition: HoloLights.h:980
HoloOLED::handleCommand
virtual void handleCommand(const char *cmd) override
See HoloLights::handleCommand()
Definition: HoloLights.h:1302
HoloLights::wagHP
void wagHP(byte type)
Definition: HoloLights.h:807
UNUSED_ARG
#define UNUSED_ARG(arg)
Definition: ReelTwo.h:25
CommandEvent.h
HoloLights::setHoloPosition
void setHoloPosition(float hpos, float vpos, int speed=0)
Definition: HoloLights.h:725
HoloLights::handleCommand
virtual void handleCommand(const char *cmd) override
Command Prefix: HP.
Definition: HoloLights.h:304
HoloLights::animate
virtual void animate() override
Runs through one frame of animation for this holoprojector instance.
Definition: HoloLights.h:417
atoi
int atoi(const char *cmd, int numdigits)
Definition: StringUtils.h:4
HoloLights::kUp
@ kUp
Holoprojector position up.
Definition: HoloLights.h:92
HoloLights::kLowerRight
@ kLowerRight
Holoprojector position lower right.
Definition: HoloLights.h:104
HoloOLED::setup
virtual void setup() override
Initalizes the OLED display and SD card.
Definition: HoloLights.h:1289
HoloLights::kLowerLeft
@ kLowerLeft
Holoprojector position lower left.
Definition: HoloLights.h:98
TEENSY_PROP_NEOPIXEL_END
#define TEENSY_PROP_NEOPIXEL_END()
Definition: ReelTwo.h:169
HoloLEDPCB::HoloLEDPCB
HoloLEDPCB()
Definition: HoloLights.h:21