RSeries astromech firmware
LogicEngineController32.h
Go to the documentation of this file.
1 #ifndef LOGICENGINECONTROLLER32_H
2 #define LOGICENGINECONTROLLER32_H
3 
4 #include "ReelTwo.h"
5 #ifndef LENGINE_DELAY_PIN
6  #define LENGINE_BUTTON_PIN 36 /* 4-button resistor lattice pin */
7 #endif
8 #ifndef LENGINE_TRIMPOT_PIN
9  #define LENGINE_TRIMPOT_PIN 39 /* analog pin to read trimpot */
10 #endif
11 #ifndef LENGINE_STATUS_PIN
12  #define LENGINE_STATUS_PIN 14 /* LED status pin */
13 #endif
14 
15 #include "dome/LogicEngine.h"
16 #include "core/AnalogMonitor.h"
17 #include "core/LEDPixelEngine.h"
18 #include <Preferences.h>
19 
20 //buttons are connected via a resistor ladder to a single ADC pin
21 // 100K, 33K, 66K and 200K
22 // so pressing each button will give us a different analog reading
23 static constexpr unsigned int LogicEngineController_kButtonVals[4]={0,850,1900,2900};
24 
25 /* LED preferences */
26 #define PREFERENCE_LOGICS "logics"
27 
37 template <byte kButtonPin = LENGINE_BUTTON_PIN, byte kTrimpotPin = LENGINE_TRIMPOT_PIN, byte kLEDStatusPin = LENGINE_STATUS_PIN>
38 class LogicEngineController : public AnimatedEvent, public SetupEvent
39 {
40 public:
41  template <uint8_t DATA_PIN = FRONT_LOGIC_PIN>
42  class StatusLED : public FastLEDPCB<WS2812B, kLEDStatusPin>
43  {
44  };
45 
50  Preferences& preferences) :
51  fPreferences(preferences),
52  fTrimPot(kTrimpotPin)
53  {
54  fLogic[0] = nullptr;
55  fLogic[1] = nullptr;
56  }
57 
58  void setWifiReset(void (*resetFunction)())
59  {
60  fWifiResetFunction = resetFunction;
61  }
62 
63  void setWifiToggle(void (*toggleFunction)())
64  {
65  fWifiToggleFunction = toggleFunction;
66  }
67 
68  virtual void setup() override
69  {
70  // ensure button pin is an input
71  pinMode(kButtonPin, INPUT);
72  pinMode(kTrimpotPin, INPUT);
73  fPrevButtonValue = analogRead(kButtonPin);
74 
75  fTrimPot.setActivityThreshold(40);
76 
77  fStatusLED.init();
78  }
79 
83  void configure(
86  {
87  fLogic[0] = FLD;
88  fLogic[1] = RLD;
89  if (FLD != nullptr)
90  {
91  fFactorySettings[0] = fSettings[0] = FLD->getSettings();
92  }
93  if (RLD != nullptr)
94  {
95  fFactorySettings[1] = fSettings[1] = RLD->getSettings();
96  }
97  if (fPreferences.isKey(PREFERENCE_LOGICS))
98  {
99  if (fPreferences.getBytes(PREFERENCE_LOGICS, fSettings, sizeof(fSettings)) == sizeof(fSettings))
100  {
101  if (FLD != nullptr)
102  {
103  FLD->changeDefaultSettings(fSettings[0]);
104  }
105  if (RLD != nullptr)
106  {
107  RLD->changeDefaultSettings(fSettings[1]);
108  }
109  }
110  }
111  }
112 
113  LogicEngineSettings& getSettings(unsigned logicNum)
114  {
115  logicNum = (logicNum & 1);
116  return fSettings[logicNum];
117  }
118 
119  // logicNum: 0==FLD 1==RLD
120  void restoreFactoryDefaults(unsigned logicNum)
121  {
122  DEBUG_PRINT("RESTORE DEFAULTS logicNum="); DEBUG_PRINTLN(logicNum);
123  logicNum = (logicNum & 1);
124  LogicEngineRenderer* logic = fLogic[logicNum];
125  LogicEngineSettings* settings = &fSettings[logicNum];
126  *settings = fFactorySettings[logicNum];
127  if (logic != nullptr)
128  {
129  commit();
130  logic->changeDefaultSettings(*settings);
131  logic->calculateAllColors();
132  }
133  }
134 
135  // logicNum: 0==FLD 1==RLD
136  // settingNum: 1==brightness 2==hue 3==fade 4==delay 5==pal
137  void changeSetting(unsigned logicNum, unsigned settingNum, unsigned val)
138  {
139  logicNum = (logicNum & 1);
140  DEBUG_PRINT("CHANGE logicNum="); DEBUG_PRINT(logicNum); DEBUG_PRINT(" setting="); DEBUG_PRINT(settingNum); DEBUG_PRINT(" val="); DEBUG_PRINTLN(val);
141  LogicEngineRenderer* logic = fLogic[logicNum];
142  LogicEngineSettings* settings = &fSettings[logicNum];
143  *settings = logic->getSettings();
144  switch (settingNum)
145  {
146  case 1:
147  settings->fBri = val;
148  break;
149  case 2:
150  settings->fHue = val;
151  break;
152  case 3:
153  settings->fFade = val;
154  break;
155  case 4:
156  settings->fDelay = val;
157  break;
158  case 5:
159  if (val >= logic->PAL_COUNT)
160  val = 0;
161  settings->fPalNum = val;
162  break;
163  }
164  if (logic != nullptr)
165  {
166  logic->changeDefaultSettings(*settings);
167  logic->calculateAllColors();
168  }
169  }
170 
171  // logicNum: 0==FLD 1==RLD
172  bool commit()
173  {
174  return (fPreferences.putBytes(PREFERENCE_LOGICS, fSettings, sizeof(fSettings)) == sizeof(fSettings));
175  }
176 
180  virtual void animate() override
181  {
182  readButtons();
183 
184  doStatusLED();
185 
186  if ((fAdjMode == 1 || fAdjMode == 2) && fLogic[fAdjMode-1] != nullptr && fTrimPot.hasChanged())
187  {
188  uint8_t val = 255 - (uint8_t)(0xFF * (fTrimPot.getValue() / 4096.0f));
189  changeSetting(fAdjMode-1, fTrimpotMode, val);
190  }
191  }
192 
193 private:
194  static constexpr unsigned kButtonVariance = 300; //changed from 200 for boards that wouldn't recognize buttons 2 & 3
195  static constexpr uint32_t kStatusLED_LowDelay = 300;
196  static constexpr uint32_t kStatusLED_NormalDelay = 1000;
197 
198  static constexpr unsigned numberOfButtons()
199  {
200  return sizeof(LogicEngineController_kButtonVals)/sizeof(LogicEngineController_kButtonVals[0]);
201  }
202 
203  Preferences& fPreferences;
204  StatusLED<> fStatusLED;
205  AnalogMonitor fTrimPot;
206  void (*fWifiResetFunction)() = nullptr;
207  void (*fWifiToggleFunction)() = nullptr;
208 
209  byte fAdjMode = 0; // 0 for no adjustments, 1 for front, 2 for rear. if adjMode>0, then trimpots will be enabled
210  byte fTrimpotMode;
211  unsigned fPrevButtonValue;
212  bool fButtonState[numberOfButtons()]; //state of each button
213  bool fPrevButtonState[numberOfButtons()];
214  uint32_t fButtonTime[numberOfButtons()+1]; //when did state of each button last change
215  LogicEngineRenderer* fLogic[2];
216  LogicEngineSettings fSettings[sizeof(fLogic)/sizeof(fLogic[0])];
217  LogicEngineSettings fFactorySettings[sizeof(fLogic)/sizeof(fLogic[0])];
218  bool fChanges[sizeof(fLogic)/sizeof(fLogic[0])] = {};
219 
220  byte fStatusColor = 0; //status LED will cycle between 4 colors depending on what mode we're in
221  byte fPrevStatusColor = 0;
222  uint32_t fPrevFlipFlopMillis = 0;
223  uint32_t fStatusFlipFlopTime = kStatusLED_NormalDelay;
224 
225  static bool inRange(int val, int minimum, int maximum)
226  {
227  return ((minimum <= val) && (val <= maximum));
228  }
229 
230  inline void fastStatusMode()
231  {
232  fStatusFlipFlopTime = kStatusLED_LowDelay;
233  }
234 
235  inline void normalStatusMode()
236  {
237  fStatusFlipFlopTime = kStatusLED_NormalDelay;
238  }
239 
240  void doStatusLED()
241  {
242  static constexpr uint8_t kStatusColors[5][4][3] = {
243  { { 2, 0, 0} , { 0, 0, 2} , { 2, 0, 0} , { 0, 0, 2} } , // red,blue,red,blue
244  { { 25, 25, 25} , { 16, 16, 16} , { 10, 10, 10} , { 2, 2, 2} } , // brightness
245  { { 2, 0, 0} , { 2, 2, 0} , { 0, 2, 0} , { 0, 0, 2} } , // hue (red , yel, green, blue)
246  { { 2, 0, 2} , { 2, 0, 1} , { 2, 0, 0} , { 2, 0, 1} } , // fade (purple, blue)
247  { { 0, 2, 0} , { 0, 2, 0} , { 0, 2, 0} , { 0, 2, 0} } // pause (all green)
248  };
249  uint32_t timeNow = millis();
250  if (timeNow - fPrevFlipFlopMillis > fStatusFlipFlopTime)
251  {
252  fPrevFlipFlopMillis = timeNow;
253  fStatusColor++;
254  if (fStatusColor == 4) fStatusColor = 0;
255  fStatusLED.fLED[0].r = kStatusColors[fTrimpotMode][fStatusColor][0];
256  fStatusLED.fLED[0].g = kStatusColors[fTrimpotMode][fStatusColor][1];
257  fStatusLED.fLED[0].b = kStatusColors[fTrimpotMode][fStatusColor][2];
258  #if USE_LEDLIB == 1
259  fStatusLED.show();
260  #else
261  FastLED.show();
262  #endif
263  }
264  }
265 
266  void readButtons()
267  {
268  uint32_t timeNow = millis();
269  unsigned buttonValue = analogRead(kButtonPin);
270  unsigned buttonReleased = numberOfButtons()+1;
271  if (!inRange(buttonValue, fPrevButtonValue - kButtonVariance, fPrevButtonValue + kButtonVariance))
272  {
273  for (byte i = 0; i < numberOfButtons(); i++)
274  {
275  if (inRange(buttonValue, LogicEngineController_kButtonVals[i] - kButtonVariance, LogicEngineController_kButtonVals[i] + kButtonVariance))
276  {
277  if (!fButtonState[i])
278  {
279  fButtonState[i] = true;
280  fButtonTime[i] = timeNow;
281  }
282  }
283  else
284  {
285  fButtonState[i] = false;
286  if (fPrevButtonState[i])
287  {
288  //okay, so a button was pressed and we're pretty sure which one it was
289  //but because of our ladder setup we could be seeing a false reading for a teeny moment
290  //so disregard any button presses that are shorter than 30ms
291  if (timeNow - fButtonTime[i] > 30)
292  {
293  buttonReleased = i;
294  }
295  }
296  }
297  fPrevButtonState[i] = fButtonState[i];
298  }
299  }
300  fPrevButtonValue = buttonValue;
301 
302  if (buttonReleased < numberOfButtons()+1)
303  {
304  DEBUG_PRINT("BUTTON: "); DEBUG_PRINTLN(buttonReleased);
305  if (buttonReleased == 0)
306  {
307  if (timeNow - fButtonTime[buttonReleased] > 5000 && fWifiResetFunction != nullptr)
308  fWifiResetFunction();
309  else if (timeNow - fButtonTime[buttonReleased] > 2000 && fWifiToggleFunction != nullptr)
310  fWifiToggleFunction();
311  }
312  else if (fLogic[0] != nullptr && fAdjMode == 0 && buttonReleased == 1)
313  {
314  if (timeNow - fButtonTime[1] > 5000)
315  {
316  DEBUG_PRINTLN("front reset defaults");
318  }
319  else if (timeNow - fButtonTime[1] > 1000)
320  {
321  DEBUG_PRINTLN("front adj mode");
322  fAdjMode = 1;
323  fTrimpotMode = 1; //brightness->hue->fade->pause
324  fastStatusMode();
325  }
326  }
327  else if (fLogic[1] != nullptr && fAdjMode == 0 && buttonReleased == 2)
328  {
329  if (timeNow - fButtonTime[2] > 5000) //changed from 1000, was preventing us going to rear adjust mode
330  {
331  DEBUG_PRINTLN("rear reset defaults");
333  }
334  else if (timeNow - fButtonTime[2] > 1000)
335  {
336  DEBUG_PRINTLN("rear adj mode");
337  fAdjMode = 2;
338  fTrimpotMode = 1; //brightness->hue->fade->pause
339  fastStatusMode();
340  }
341  }
342  else if ((fAdjMode==1 || fAdjMode==2) && (buttonReleased == 1 || buttonReleased == 2))
343  {
344  if (timeNow - fButtonTime[buttonReleased] > 1000)
345  {
346  DEBUG_PRINTLN("save settings");
347  commit();
348  fAdjMode = 0;
349  normalStatusMode();
350  fTrimpotMode = 0;
351  }
352  else if (timeNow - fButtonTime[1] > 30)
353  {
354  fTrimpotMode++;
355  if (fTrimpotMode > 4) fTrimpotMode = 1;
356  #ifdef USE_DEBUG
357  if (fTrimpotMode==1) DEBUG_PRINTLN(" bri");
358  else if (fTrimpotMode==2) DEBUG_PRINTLN(" hue");
359  else if (fTrimpotMode==3) DEBUG_PRINTLN(" fade");
360  else if (fTrimpotMode==4) DEBUG_PRINTLN(" pause");
361  #endif
362  }
363  }
364  if ((fAdjMode == 1 || fAdjMode == 2) && buttonReleased == 3 && timeNow - fButtonTime[4] > 30)
365  {
366  //change up palette number
367  if (fLogic[fAdjMode-1] != nullptr)
368  {
369  changeSetting(fAdjMode-1, 5, fLogic[fAdjMode-1]->getCurrentPalette()+1);
370  }
371  }
372  }
373  }
374 };
375 
377 
378 #endif
LEDPixelEngine.h
LogicEngineController::changeSetting
void changeSetting(unsigned logicNum, unsigned settingNum, unsigned val)
Definition: LogicEngineController32.h:137
LogicEngineSettings::fBri
byte fBri
Definition: LogicEngine.h:200
LogicEngineSettings::fDelay
byte fDelay
Definition: LogicEngine.h:198
LogicEngineSettings
Current settings for LogicEngine hardware.
Definition: LogicEngine.h:176
LogicEngineRenderer
Base class renderer for both front and rear RSeries logics.
Definition: LogicEngine.h:597
DEBUG_PRINT
#define DEBUG_PRINT(s)
Definition: ReelTwo.h:189
LogicEngineController::restoreFactoryDefaults
void restoreFactoryDefaults(unsigned logicNum)
Definition: LogicEngineController32.h:120
LogicEngineController::commit
bool commit()
Definition: LogicEngineController32.h:172
ReelTwo.h
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
SetupEvent
Base class for all devices that require setup that cannot happen in the constructor....
Definition: SetupEvent.h:15
AnalogMonitor::setActivityThreshold
void setActivityThreshold(float newThreshold)
Definition: AnalogMonitor.h:170
PREFERENCE_LOGICS
#define PREFERENCE_LOGICS
Definition: LogicEngineController32.h:26
LogicEngineController::configure
void configure(LogicEngineRenderer *FLD, LogicEngineRenderer *RLD)
Check the adjustment switch and read trimpots and adjust settings.
Definition: LogicEngineController32.h:83
DEBUG_PRINTLN
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:188
AnalogMonitor.h
LogicEngineController::StatusLED
Definition: LogicEngineController32.h:42
AnalogMonitor::hasChanged
bool hasChanged()
Definition: AnalogMonitor.h:117
AnalogMonitor::getValue
int getValue()
Definition: AnalogMonitor.h:101
LogicEngineRenderer::changeDefaultSettings
virtual void changeDefaultSettings(LogicEngineSettings &settings)=0
LogicEngineSettings::fPalNum
byte fPalNum
Definition: LogicEngine.h:199
LogicEngineSettings::fHue
byte fHue
Definition: LogicEngine.h:197
LogicEngineController
Settings adjust for LogicEngine logics.
Definition: LogicEngineController.h:60
LogicEngineController::LogicEngineController
LogicEngineController(Preferences &preferences)
Constructor.
Definition: LogicEngineController32.h:49
LogicEngineController::animate
virtual void animate() override
Check the adjustment switch and read trimpots and adjust settings.
Definition: LogicEngineController32.h:180
LogicEngineRenderer::getSettings
LogicEngineSettings getSettings()
Definition: LogicEngine.h:1403
LogicEngineController::setWifiToggle
void setWifiToggle(void(*toggleFunction)())
Definition: LogicEngineController32.h:63
LogicEngine.h
LogicEngineController::setup
virtual void setup() override
Definition: LogicEngineController32.h:68
LogicEngineControllerDefault
LogicEngineController LogicEngineControllerDefault
Definition: LogicEngineController32.h:376
LogicEngineRenderer::calculateAllColors
void calculateAllColors(byte colorPalNum, byte brightVal)
Definition: LogicEngine.h:1238
LogicEngineSettings::fFade
byte fFade
Definition: LogicEngine.h:196
LogicEngineController::setWifiReset
void setWifiReset(void(*resetFunction)())
Definition: LogicEngineController32.h:58
LogicEngineController::getSettings
LogicEngineSettings & getSettings(unsigned logicNum)
Definition: LogicEngineController32.h:113
LogicEngineDefaults::PAL_COUNT
static constexpr byte PAL_COUNT
Definition: LogicEngine.h:111
AnalogMonitor
Used for eliminating noise in analogRead inputs without decreasing responsiveness....
Definition: AnalogMonitor.h:51