-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathSimWheelTypes.h
859 lines (801 loc) · 20.4 KB
/
SimWheelTypes.h
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
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
/**
* @file SimWheelTypes.h
*
* @author Ángel Fernández Pineda. Madrid. Spain.
* @date 2022-02-27
* @brief Types and constants used everywhere
*
* @note Some types are renamed just for portability
*
* @copyright Licensed under the EUPL
*
*/
#ifndef __SIM_WHEEL_TYPES_H__
#define __SIM_WHEEL_TYPES_H__
#include <stdint.h>
#include <vector>
#include <string>
#include "hal/gpio_types.h" // declares gpio_num_t
#include "esp32-hal.h"
/**
* @brief A bit array which assembles the state of every button, being the least significant bit
* the button numbered as 0, and the most significant bit the button numbered as 63.
* A bit set to 1 means the button is pressed, 0 means not pressed.
* May be used to identify a number of buttons, too.
*/
typedef uint64_t inputBitmap_t;
/**
* @brief A button number, starting from zero.
*
*/
typedef uint8_t inputNumber_t;
#define UNSPECIFIED_INPUT_NUMBER 0xFF // Input number is not required or is implicit or is unknown
#define MAX_INPUT_NUMBER 63 // Maximum allowed input number, including itself
#define MAX_USER_INPUT_NUMBER 127 // Maximum allowed input number, including itself, in user-defined button maps
// Well-known input numbers for PC game controllers
#define JOY_A 0
#define JOY_B 1
#define JOY_X 2
#define JOY_Y 3
#define JOY_LB 4
#define JOY_RB 5
#define JOY_LSHIFT_PADDLE 4
#define JOY_RSHIFT_PADDLE 5
#define JOY_BACK 6
#define JOY_START 7
#define JOY_LTHUMBSTICK_CLICK 8
#define JOY_RTHUMBSTICK_CLICK 9
/**
* @brief Array of GPIO pins
*
*/
typedef std::vector<gpio_num_t> gpio_num_array_t;
/**
* @brief Specification of input numbers for a button matrix
*
*/
class ButtonMatrixInputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to a button matrix
*
* @param selectorPin Selector pin (GPIO number or alias)
* @param inputPin Selector pin (GPIO number or alias)
* @param number Input number assigned to the button
* @return ButtonMatrixInputSpec& This object (to chain calls)
*/
virtual ButtonMatrixInputSpec &inputNumber(
gpio_num_t selectorPin,
gpio_num_t inputPin,
inputNumber_t number) = 0;
};
/**
* @brief 74HC4051N pin tags for switches
* or any other 8-channel multiplexer
*
*/
enum class mux8_pin_t
{
A0 = 0,
A1,
A2,
A3,
A4,
A5,
A6,
A7
};
/**
* @brief Specification of input numbers for multiplexed switches
* (8 channels)
*
*/
class Multiplexers8InputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to a multiplexer
*
* @param inputPin Input pin (GPIO number or alias)
* @param pin Pin name in the chip to which the button is connected
* @param number Input number assigned to the button
* @return Multiplexers8InputSpec& This object (to chain calls)
*/
virtual Multiplexers8InputSpec &inputNumber(
gpio_num_t inputPin,
mux8_pin_t pin,
inputNumber_t number) = 0;
};
/**
* @brief CD74HCx4067 pin tags for switches
* or any other 16-channel multiplexer
*
*/
enum class mux16_pin_t
{
I0 = 0,
I1,
I2,
I3,
I4,
I5,
I6,
I7,
I8,
I9,
I10,
I11,
I12,
I13,
I14,
I15,
};
/**
* @brief Specification of input numbers for multiplexed switches
* (16 channels)
*
*/
class Multiplexers16InputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to a multiplexer
*
* @param inputPin Input pin (GPIO number or alias)
* @param pin Pin name in the chip to which the button is connected
* @param number Input number assigned to the button
* @return Multiplexers16InputSpec& This object (to chain calls)
*/
virtual Multiplexers16InputSpec &inputNumber(
gpio_num_t inputPin,
mux16_pin_t pin,
inputNumber_t number) = 0;
};
/**
* @brief ADG732 pin tags for switches
* or any other 32-channel multiplexer
*
*/
enum class mux32_pin_t
{
S1 = 0,
S2,
S3,
S4,
S5,
S6,
S7,
S8,
S9,
S10,
S11,
S12,
S13,
S14,
S15,
S16,
S17,
S18,
S19,
S20,
S21,
S22,
S23,
S24,
S25,
S26,
S27,
S28,
S29,
S30,
S31,
S32
};
/**
* @brief Specification of input numbers for multiplexed switches
* (32 channels)
*
*/
class Multiplexers32InputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to a multiplexer
*
* @param inputPin Input pin (GPIO number or alias)
* @param pin Pin name in the chip to which the button is connected
* @param number Input number assigned to the button
* @return Multiplexers16InputSpec& This object (to chain calls)
*/
virtual Multiplexers32InputSpec &inputNumber(
gpio_num_t inputPin,
mux32_pin_t pin,
inputNumber_t number) = 0;
};
/**
* @brief 74HC165N pin tags for switches
*
*/
enum class sr8_pin_t
{
H = 0,
G,
F,
E,
D,
C,
B,
A,
SER
};
/**
* @brief Specification of input numbers for shift registers
*
*/
class ShiftRegisters8InputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to a shift registers chain
*
* @param indexInChain Position of a chip in the chain
* @param pin Pin name in the chip to which the button is connected
* @param number Input number assigned to the button
* @return ShiftRegisters8InputSpec& This object (to chain calls)
*/
virtual ShiftRegisters8InputSpec &inputNumber(
uint8_t indexInChain,
sr8_pin_t pin,
inputNumber_t number) = 0;
};
/**
* @brief MCP23017 pin tags for switches
*
*/
enum class MCP23017_pin_t
{
GPA0 = 0,
GPA1,
GPA2,
GPA3,
GPA4,
GPA5,
GPA6,
GPA7,
GPB0,
GPB1,
GPB2,
GPB3,
GPB4,
GPB5,
GPB6,
GPB7
};
/**
* @brief Specification of input numbers for MCP23017 GPIO expanders
*
*/
class MCP23017InputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to MCP23017 chip
*
* @param pin Pin name in the chip to which the button is connected
* @param number Input number assigned to the button
* @return MCP23017InputSpec& This object (to chain calls)
*/
virtual MCP23017InputSpec &inputNumber(MCP23017_pin_t pin, inputNumber_t number) = 0;
};
/**
* @brief MCP23017 pin tags for switches
*
*/
enum class PCF8574_pin_t
{
P0 = 0,
P1,
P2,
P3,
P4,
P5,
P6,
P7
};
/**
* @brief Specification of input numbers for PCF8574 GPIO expanders
*
*/
class PCF8574InputSpec
{
public:
/**
* @brief Abstract definition of buttons attached to PCF8574 chip
*
* @param pin Pin name in the chip to which the button is connected
* @param number Input number assigned to the button
* @return PCF8574InputSpec& This object (to chain calls)
*/
virtual PCF8574InputSpec &inputNumber(PCF8574_pin_t pin, inputNumber_t number) = 0;
};
/**
* @brief The value of a joystick's axis
*
* @note DO NOT CHANGE. hidImplementation and userSettings depends on it.
*/
typedef uint8_t clutchValue_t;
#define CLUTCH_NONE_VALUE 0
#define CLUTCH_FULL_VALUE 254
#define CLUTCH_DEFAULT_VALUE 127
#define CLUTCH_1_4_VALUE 64
#define CLUTCH_3_4_VALUE 192
#define CLUTCH_INVALID_VALUE 255
/**
* @brief Value read from an ADC pin
*
*/
typedef uint16_t analogReading_t;
/**
* @brief A combination of input numbers
*
*/
typedef std::vector<inputNumber_t> inputNumberCombination_t;
/**
* @brief Transform a button number to an input bitmap.
* For example, BITMAP(2) returns 0b00000100
*
*/
#define BITMAP(n) (1ULL << static_cast<inputBitmap_t>(n))
/**
* @brief Return a mask for a number of consecutive buttons (`count`) starting from `first`.
* A mask is a bit array where each bit determines if a button is to be used or not.
* 1 means **not** used. 0 means in use.
* Masks are required to combine the state from multiple input bitmaps.
* For example, BITMASK(2,2) returns 0b(...)11110011 which means that
* buttons numbered 2 and 3 are in use.
*/
#define BITMASK(count, first) ~(((1ULL << static_cast<inputBitmap_t>(count)) - 1ULL) << static_cast<inputBitmap_t>(first))
/**
* @brief Return the logical negation of a bit mask
*
*/
#define NBITMASK(count, first) (((1ULL << static_cast<inputBitmap_t>(count)) - 1ULL) << static_cast<inputBitmap_t>(first))
/**
* @brief Debounce time for buttons, in system ticks
*
*/
#define DEBOUNCE_TICKS pdMS_TO_TICKS(30)
/**
* @brief Priority of background tasks
*
*/
#define INPUT_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
/**
* @brief User-selected function of the clutch paddles
*
*/
typedef enum
{
/// F1-Style clutch. Must be the first in the enum: do not change
CF_CLUTCH = 0,
/// Independent axes
CF_AXIS,
/// "ALT" mode
CF_ALT,
/// Regular buttons. Must be the last in the enum: do not change
CF_BUTTON,
/// Launch control. Left paddle is master
CF_LAUNCH_CONTROL_MASTER_LEFT,
/// Launch control. Right paddle is master
CF_LAUNCH_CONTROL_MASTER_RIGHT
} clutchFunction_t;
/**
* @brief Default autosave delay (in microseconds)
*
*/
#define DEFAULT_AUTOSAVE_us 20 * 1000 * 1000
/**
* @brief Time to wait for connection before power off (in seconds)
*
*/
#define AUTO_POWER_OFF_DELAY_SECS 60
/**
* @brief Supported power latch modes
*
*/
typedef enum
{
/// Power on when open drain, power off when low voltage
POWER_OPEN_DRAIN,
/// Power on when low voltage, power off when high voltage
POWER_OFF_HIGH,
/// Power on when high voltage, power off when low voltage
POWER_OFF_LOW
} powerLatchMode_t;
/**
* @brief Battery level to report when unknown (percentage)
*
*/
#define UNKNOWN_BATTERY_LEVEL 66
/**
* @brief Enumeration of device capabilities
*
*/
typedef enum
{
/// Has digital clutch paddles (switches)
CAP_CLUTCH_BUTTON = 0,
/// Has analog clutch paddles (potentiometers)
CAP_CLUTCH_ANALOG = 1,
/// Has "ALT" buttons
CAP_ALT = 2,
/// Has a directional pad
CAP_DPAD = 3,
/// Battery-operated
CAP_BATTERY = 4,
/// Has battery calibration data
CAP_BATTERY_CALIBRATION_AVAILABLE = 5,
/// Able to display powertrain telemetry data
CAP_TELEMETRY_POWERTRAIN = 6,
/// Able to display ECU telemetry data
CAP_TELEMETRY_ECU = 7,
/// Able to display race control telemetry data
CAP_TELEMETRY_RACE_CONTROL = 8,
/// Able to display telemetry data for gauges
CAP_TELEMETRY_GAUGES = 9,
/// Has one or more rotary encoders
CAP_ROTARY_ENCODERS = 10
} deviceCapability_t;
/**
* @brief Simple commands accepted from a feature HID report
*
*/
typedef enum
{
/// Not a command, reserved to avoid mistakes
CMD_RESERVED = 0,
/// Recalibrate analog axes (if any)
CMD_AXIS_RECALIBRATE = 1,
/// Restart battery auto-calibration
CMD_BATT_RECALIBRATE = 2,
/// Reset buttons map to factory defaults
CMD_RESET_BUTTONS_MAP = 3,
/// Save all user settings to flash memory immediately
CMD_SAVE_NOW = 4,
/// Reverse left axis (if any)
CMD_REVERSE_LEFT_AXIS = 5,
/// Reverse right axis (if any)
CMD_REVERSE_RIGHT_AXIS = 6,
/// Display all pixels in all pixel groups
CMD_SHOW_PIXELS = 7,
/// Turn off all pixels in all groups
CMD_RESET_PIXELS = 8
} simpleCommands_t;
/**
* @brief Telemetry data
*
*/
typedef struct
{
/**
* @brief Identifies a telemetry frame. For internal use. Do not overwrite.
*
*/
uint32_t frameID;
/**
* @brief Powertrain telemetry
*
*/
struct
{
/// Display character for current gear
char gear = ' ';
/// Revolutions per minute
uint16_t rpm = 0;
/// Percentage of RPM
uint8_t rpmPercent = 0;
/// Non-zero at maximum torque
uint8_t shiftLight1 = 0;
/// Non-zero at maximum power
uint8_t shiftLight2 = 0;
/// True at maximum RPM
bool revLimiter = false;
/// True if the engine is running
bool engineStarted = false;
/// Speed in user-defined units (Kph or Mph)
uint16_t speed = 0;
} powertrain;
/**
* @brief ECU telemetry
*
*/
struct
{
/// ABS is engaged
bool absEngaged = false;
/// TC is engaged
bool tcEngaged = false;
/// DRS is engaged
bool drsEngaged = false;
/// The pit limiter is engaged
bool pitLimiter = false;
/// True when fuel is low
bool lowFuelAlert = false;
/// Driver-selected ABS mode
uint8_t absLevel = 0;
/// Driver-selected TC mode
uint8_t tcLevel = 0;
/// Driver-selected TC Cut mode (NOTE: currently not available)
uint8_t tcCut = 0;
/// Percentage of brake bias towards front wheels
uint8_t brakeBias = 0;
} ecu;
/**
* @brief Race control telemetry
*
*/
struct
{
bool blackFlag = false;
bool blueFlag = false;
bool checkeredFlag = false;
bool greenFlag = false;
bool orangeFlag = false;
bool whiteFlag = false;
bool yellowFlag = false;
/// Remaining laps to the end of the session. Zero if does not apply.
uint16_t remainingLaps = 0;
/// Remaining time to the end of the session, in minutes. Zero if does not apply.
uint16_t remainingMinutes = 0;
} raceControl;
/**
* @brief Gauges telemetry
*
*/
struct
{
/// Percentage of turbo pressure
uint8_t relativeTurboPressure = 0;
/// Turbo pressure in bars
float absoluteTurboPressure = 0.0;
/// Water temperature in user-defined units (Celsius or Fahrenheit)
uint16_t waterTemperature = 0;
/// Oil pressure in bars
float oilPressure = 0.0;
/// Oil temperature in user-defined units (Celsius or Fahrenheit)
uint16_t oilTemperature = 0;
/// Percentage of remaining fuel
uint8_t relativeRemainingFuel = 0;
/// Remaining fuel in user-defined units (litres or gallons)
uint16_t absoluteRemainingFuel = 0;
} gauges;
} telemetryData_t;
/**
* @brief Abstract interface for notifications and telemetry display.
*
*/
class AbstractUserInterface
{
protected:
/**
* @brief Simple timer.
*
* @note To be used in AbstractUserInterface::serveSingleFrame().
* Initialize the timer variable to zero.
*
* @param timerVariable Timer variable.
* @param elapsedTimeMs Time elapsed since last call in miliseconds.
* @param timeLimitMs Expiration time in miliseconds.
* @return uint32_t The count of times the timer has expired in the elapsed time.
*/
uint32_t frameTimer(
uint32_t &timerVariable,
uint32_t elapsedTimeMs,
uint32_t timeLimitMs)
{
timerVariable += elapsedTimeMs;
uint32_t result = timerVariable / timeLimitMs;
timerVariable %= timeLimitMs;
return result;
};
public:
/// Index of this implementor. Do not overwrite.
uint8_t index;
/// Set to true to receive and use powertrain telemetry data
bool requiresPowertrainTelemetry = false;
/// Set to true to receive and use ECU telemetry data
bool requiresECUTelemetry = false;
/// Set to true to receive and use race control telemetry data
bool requiresRaceControlTelemetry = false;
/// Set to true to receive and use telemetry data for gauges
bool requiresGaugeTelemetry = false;
public:
/**
* @brief Called just once after initialization.
*
* @note Called in a low priority thread.
*/
virtual void onStart() {};
/**
* @brief Notify new telemetry data
*
* @param pTelemetryData Pointer to telemetry data. Can be null.
* Safe to store for later use.
*
* @note For this method to get called,
* user code must meet the following requirements:
* - Frames-per-second must be set to non-zero. See notify::begin().
* - At instance creation, one of the requiresXXXTelemetry attributes
* must be set to true.
*
* @note Always called just before serveSingleFrame().
* This method may draw a display frame into a buffer,
* while serveSingleFrame() just displays that frame buffer.
*
* @note @p pTelemetryData is null when no telemetry data has been
* received in the previous two seconds. May be used
* to turn the display off.
*
* @note Must not enter an infinite loop. Must return as soon as possible.
*
* @note Called in a low priority thread.
*/
virtual void onTelemetryData(const telemetryData_t *pTelemetryData) {};
/**
* @brief Draw a single frame.
*
* @param elapsedMs Elapsed milliseconds since last call.
*
* @note Called at timed intervals when no notifications are pending.
* Not called at all if frames per second is set to 0.
* See notify::begin(). Do not assume perfect timing.
*
* @note Must not enter an infinite loop. Must return as soon as possible.
*
* @note Called in a low priority thread.
*/
virtual void serveSingleFrame(uint32_t elapsedMs) {};
/**
* @brief Notify a change in current bite point.
*
* @note Read userSetting::bitePoint to know the last value
* @note Called in a low priority thread.
*/
virtual void onBitePoint() {};
/**
* @brief Notify device is connected.
*
* @note Called in a low priority thread.
*/
virtual void onConnected() {};
/**
* @brief Notify device is in discovery mode.
*
* @note Called in a low priority thread.
*
* @note Not called in the USB implementation.
*/
virtual void onBLEdiscovering() {};
/**
* @brief Notify low battery.
*
* @note Called in a low priority thread.
* @note Called at timed intervals while the low battery
* condition persists.
*/
virtual void onLowBattery() {};
/**
* @brief Cut power to the UI hardware.
*
* @note This is a command, not a notification. Not reversible.
*
*/
virtual void shutdown() {};
};
/**
* @brief Array of user interface implementations.
*
*/
typedef std::vector<AbstractUserInterface *> notificationImplementorsArray_t;
/**
* @brief Available RGB LED groups for pixel control
*
*/
typedef enum
{
/// Telemetry leds group
GRP_TELEMETRY = 0,
/// Buttons lighting group
GRP_BUTTONS,
/// Individual leds group
GRP_INDIVIDUAL
} pixelGroup_t;
/**
* @brief Pixel driver
*
*/
typedef enum
{
/// WS2811 driver
WS2811,
/// WS2812 family
WS2812,
/// WS2815 family
WS2815,
/// SK6812 driver
SK6812,
/// UCS1903 driver
UCS1903
} pixel_driver_t;
/**
* @brief Byte order of pixel data
*
*/
typedef enum
{
/// Auto-detect based on pixel driver
AUTO,
/// Red-green-blue
RGB,
/// Red-blue-green
RBG,
/// Green-red-blue
GRB,
/// Green-blue-red
GBR,
/// Blue-red-green
BRG,
/// Blue-green-red
BGR
} pixel_format_t;
/**
* @brief Notifications using the pixel control interface
*
*/
class PixelControlNotification : public AbstractUserInterface
{
private:
virtual void onStart() override;
virtual void onBitePoint() override;
virtual void onConnected() override;
virtual void onBLEdiscovering() override;
virtual void onLowBattery() override;
public:
/**
* @brief Called just once after initialization.
*
* @note Called in a low priority thread.
*/
virtual void pixelControl_OnStart();
/**
* @brief Notify a change in current bite point.
*
* @note Read userSetting::bitePoint to know the last value
* @note Called in a low priority thread.
*/
virtual void pixelControl_OnBitePoint();
/**
* @brief Notify device is connected.
*
* @note Called in a low priority thread.
*/
virtual void pixelControl_OnConnected();
/**
* @brief Notify device is in discovery mode.
*
* @note Called in a low priority thread.
*
* @note Not called in the USB implementation.
*/
virtual void pixelControl_OnBLEdiscovering();
/**
* @brief Notify low battery.
*
* @note Called in a low priority thread.
* @note Called at timed intervals while the low battery
* condition persists.
*/
virtual void pixelControl_OnLowBattery();
};
#endif