OpenSourceSimWheelESP32
Open-source wireless steering wheel/button box for ESP32 boards
Loading...
Searching...
No Matches
SimWheelTypes.hpp
Go to the documentation of this file.
1
12#pragma once
13
14//-------------------------------------------------------------------
15// Global macros
16//-------------------------------------------------------------------
17
18#if CD_CI
19
21
22#define GPIO_IS_VALID_GPIO(pin) (pin < 100)
23#define TEST_NO_OUTPUT_GPIO 80
24#define GPIO_IS_VALID_OUTPUT_GPIO(pin) (pin < TEST_NO_OUTPUT_GPIO)
25#define TEST_RTC_GPIO1 40
26#define TEST_RTC_GPIO2 49
27#define GPIO_IS_VALID_RTC_GPIO(pin) ((pin >= TEST_RTC_GPIO1) && (pin <= TEST_RTC_GPIO2))
28#define TEST_RESERVED_GPIO 50
29
31
32#else
33
35#define GPIO_IS_VALID_RTC_GPIO(pin) rtc_gpio_is_valid_gpio(static_cast<gpio_num_t>(pin))
36
37#endif
38
39//-------------------------------------------------------------------
40// Imports
41//-------------------------------------------------------------------
42
43#include <cstdint>
44#include <string>
45#include <stdexcept>
46#include <set>
47#include <vector>
48#include <initializer_list>
49#include <map>
50#include <algorithm>
51
52#if !CD_CI
53#include "driver/rtc_io.h" // For rtc_gpio_is_valid_gpio()
54#include "hal/gpio_types.h" // For gpio_num_t
55#include "driver/gpio.h" // For GPIO_IS_VALID... and others
56#include "esp32-hal-psram.h" // For psramFound()
57#endif
58
59//-------------------------------------------------------------------
60// Exceptions
61//-------------------------------------------------------------------
62
68class invalid_input_number : public std::runtime_error
69{
70public:
76 invalid_input_number(uint8_t value)
77 : std::runtime_error(
78 "The input number " +
79 std::to_string(value) +
80 " is out of range [0,127]") {}
87 : std::runtime_error(
88 "Trying to use an unspecified input number.") {}
89
90 virtual ~invalid_input_number() noexcept {}
91};
92
97class gpio_error : public std::runtime_error
98{
99public:
107 gpio_error(uint8_t value, const std::string &reason)
108 : std::runtime_error(
109 "Invalid GPIO number " +
110 std::to_string(value) +
111 ". Reason: " +
112 reason) {}
113};
114
119class empty_input_number_set : public std::runtime_error
120{
121public:
127 empty_input_number_set(const std::string &hardware)
128 : std::runtime_error(
129 "No input numbers were given to: " + hardware) {}
130
131 virtual ~empty_input_number_set() noexcept {}
132};
133
140class unknown_input_number : public std::runtime_error
141{
142public:
148 unknown_input_number(const std::string &usage)
149 : std::runtime_error(
150 "There is an input number not assigned to a hardware input. Usage: " +
151 usage) {}
152
153 virtual ~unknown_input_number() noexcept {}
154};
155
156//-------------------------------------------------------------------
157// Utility functions
158//-------------------------------------------------------------------
159
170inline int map_value(int x, int in_min, int in_max, int out_min, int out_max)
171{
172 const int run = in_max - in_min;
173 if (run == 0)
174 return 0;
175 const int rise = out_max - out_min;
176 const int delta = x - in_min;
177 return (delta * rise) / run + out_min;
178}
179
180//-------------------------------------------------------------------
181// Unspecified values
182//-------------------------------------------------------------------
183
188enum class UNSPECIFIED
189{
191 VALUE = 0xFF
192};
193
194//-------------------------------------------------------------------
195// Input Bitmap
196//-------------------------------------------------------------------
197
198// Note: fucking Arduino macro
199#undef bit
200
206{
208 uint64_t low{0ULL};
210 uint64_t high{0ULL};
211
213 explicit constexpr operator bool()
214 {
215 return low || high;
216 }
217
225 constexpr bool bit(uint8_t n) const noexcept
226 {
227 if (n < 64)
228 return (1ULL << n) & low;
229 else if (n < 128)
230 return (1ULL << (n - 64) & high);
231 else
232 return false;
233 }
234
241 constexpr void set_bit(uint8_t n, bool value = true) noexcept
242 {
243 if (n < 64)
244 {
245 if (value)
246 low |= (1ULL << n);
247 else
248 low &= ~(1ULL << n);
249 }
250 else if (n < 128)
251 {
252 n -= 64;
253 if (value)
254 high |= (1ULL << n);
255 else
256 high &= ~(1ULL << n);
257 }
258 }
259
266 constexpr uint128_t &operator|=(const uint128_t &rhs) noexcept
267 {
268 low |= rhs.low;
269 high |= rhs.high;
270 return *this;
271 }
272
279 constexpr uint128_t &operator&=(const uint128_t &rhs) noexcept
280 {
281 low &= rhs.low;
282 high &= rhs.high;
283 return *this;
284 }
285
292 constexpr uint128_t &operator^=(const uint128_t &rhs) noexcept
293 {
294 low ^= rhs.low;
295 high ^= rhs.high;
296 return *this;
297 }
298
305 static constexpr uint128_t bitmap(uint8_t n) noexcept
306 {
307 if (n < 64)
308 return {
309 .low = (1ULL << n),
310 .high = 0ULL,
311 };
312 else if (n < 128)
313 return {
314 .low = 0ULL,
315 .high = (1ULL << (n - 64)),
316 };
317 else
318 return {};
319 }
320
326 static constexpr uint128_t neg() noexcept
327 {
328 return {
329 .low = ~0ULL,
330 .high = ~0ULL,
331 };
332 }
333};
334
335static_assert(
336 sizeof(uint128_t) == 16,
337 "Wrong size in the uint128_t data type. Check memory alignment.");
338
346inline constexpr uint128_t operator<<(
347 const uint128_t &source,
348 ::std::size_t n) noexcept
349{
350 if (n == 0)
351 {
352 return source;
353 }
354 else
355 {
356 uint128_t result;
357 if (n < 64)
358 {
359 result.low = (source.low << n);
360 result.high = (source.high << n) | (source.low >> (64 - n));
361 }
362 else
363 {
364 result.low = 0ULL;
365 result.high = source.low << (n - 64);
366 }
367 return result;
368 }
369}
370
378inline constexpr uint128_t operator>>(
379 const uint128_t &source,
380 ::std::size_t n) noexcept
381{
382 if (n == 0)
383 {
384 return source;
385 }
386 else
387 {
388 uint128_t result;
389 if (n < 64)
390 {
391 result.low = (source.low >> n) | (source.high << (64 - n));
392 result.high = (source.high >> n);
393 }
394 else
395 {
396 result.high = 0ULL;
397 result.low = source.high >> (n - 64);
398 }
399 return result;
400 }
401}
402
410inline constexpr uint128_t operator|(uint128_t a, uint128_t b) noexcept
411{
412 return {
413 .low = a.low | b.low,
414 .high = a.high | b.high,
415 };
416}
417
425inline constexpr uint128_t operator&(uint128_t a, uint128_t b) noexcept
426{
427 return {
428 .low = a.low & b.low,
429 .high = a.high & b.high,
430 };
431}
432
440inline constexpr uint128_t operator^(uint128_t a, uint128_t b) noexcept
441{
442 return {
443 .low = a.low ^ b.low,
444 .high = a.high ^ b.high,
445 };
446}
447
454inline constexpr uint128_t operator~(uint128_t a) noexcept
455{
456 return {
457 .low = ~(a.low),
458 .high = ~(a.high),
459 };
460}
461
470inline constexpr bool operator==(uint128_t a, uint128_t b) noexcept
471{
472 return (a.low == b.low) && (a.high == b.high);
473}
474
483inline constexpr bool operator!=(uint128_t a, uint128_t b)
484{
485 return (a.low != b.low) || (a.high != b.high);
486}
487
488//-------------------------------------------------------------------
489// Input numbers
490//-------------------------------------------------------------------
491
498{
499public:
501 constexpr InputNumber() noexcept
502 {
503 _value = 0xFF;
504 }
505
511 constexpr InputNumber(uint8_t value)
512 {
513 if (value >= 128)
514 throw invalid_input_number(value);
515 _value = value;
516 }
517
523 constexpr InputNumber(UNSPECIFIED value) noexcept
524 {
525 _value = 0xFF;
526 }
527
533 constexpr InputNumber(const InputNumber &number) = default;
534
540 constexpr InputNumber(InputNumber &&number) = default;
541
548 constexpr InputNumber &operator=(const InputNumber &number) = default;
549
555 constexpr InputNumber &operator=(InputNumber &&number) = default;
556
562 explicit constexpr operator uint128_t() const
563 {
564 return uint128_t::bitmap(_value);
565 }
566
572 constexpr operator uint8_t() const
573 {
574 return _value;
575 }
576
584 bool constexpr operator==(const UNSPECIFIED value) const
585 {
586 return (_value > 127);
587 }
588
596 bool constexpr operator!=(const UNSPECIFIED value) const noexcept
597 {
598 return (_value < 128);
599 }
600
602
603 inline constexpr bool operator==(const InputNumber value) const noexcept
604 {
605 return (_value == value._value);
606 }
607 inline constexpr bool operator!=(const InputNumber value) const noexcept
608 {
609 return (_value != value._value);
610 }
611 inline constexpr bool operator<(const InputNumber value) const noexcept
612 {
613 return (_value < value._value);
614 }
615 inline constexpr bool operator<=(const InputNumber value) const noexcept
616 {
617 return (_value <= value._value);
618 }
619 inline constexpr bool operator>(const InputNumber value) const noexcept
620 {
621 return (_value > value._value);
622 }
623 inline constexpr bool operator>=(const InputNumber value) const noexcept
624 {
625 return (_value >= value._value);
626 }
627
629
634 void book() const
635 {
636 _registered.set_bit(_value, true);
637 }
638
643 void unbook() const
644 {
645 _registered.set_bit(_value, false);
646 }
647
652 static void bookAll()
653 {
654 _registered = uint128_t::neg();
655 }
656
664 static bool booked(InputNumber inputNumber)
665 {
666 return _registered.bit(inputNumber._value);
667 }
668
676 static bool booked(uint8_t inputNumber)
677 {
678 return _registered.bit(inputNumber);
679 }
680
686 static uint128_t booked() { return _registered; }
687
693 static void unbook(uint8_t inputNumber)
694 {
695 _registered.set_bit(inputNumber, false);
696 }
697
703 static void book(uint8_t inputNumber)
704 {
705 _registered.set_bit(inputNumber, true);
706 }
707
708#if CD_CI
709 static void clearBook()
710 {
711 _registered.low = 0ULL;
712 _registered.high = 0ULL;
713 };
714#endif
715
716private:
717 uint8_t _value;
718 inline static uint128_t _registered{};
719};
720
726{
729
736 std::initializer_list<InputNumber> items) noexcept : uint128_t{}
737 {
738 for (auto n : items)
739 set_bit(n);
740 }
741
747 constexpr InputNumberCombination(const uint128_t &from)
748 : uint128_t{from} {};
749
756 : uint128_t{from} {};
757
763 constexpr uint8_t size() const noexcept
764 {
765 uint8_t result = 0;
766 for (uint8_t i = 0; i < 128; i++)
767 if (bit(i))
768 result++;
769 return result;
770 }
771
774 const InputNumberCombination &) noexcept = default;
775
778 InputNumberCombination &&) noexcept = default;
779
781 constexpr InputNumberCombination &operator=(
782 const InputNumberCombination &) noexcept = default;
783
785 constexpr InputNumberCombination &operator=(
786 InputNumberCombination &&) = default;
787
788 // NEEDED???
789 // /**
790 // * @brief Typecast to vector
791 // *
792 // * @return std::vector<uint8_t> Vector of input numbers
793 // */
794 // operator std::vector<uint8_t>()
795 // {
796 // std::vector<uint8_t> result = {};
797 // for (uint8_t n = 0; n < 128; n++)
798 // {
799 // if (bit(n))
800 // result.push_back(n);
801 // }
802 // return result;
803 // }
804};
805
806// Well-known input numbers for PC game controllers
807#define JOY_A 0
808#define JOY_B 1
809#define JOY_X 2
810#define JOY_Y 3
811#define JOY_LB 4
812#define JOY_RB 5
813#define JOY_LSHIFT_PADDLE 4
814#define JOY_RSHIFT_PADDLE 5
815#define JOY_BACK 6
816#define JOY_START 7
817#define JOY_LTHUMBSTICK_CLICK 8
818#define JOY_RTHUMBSTICK_CLICK 9
819
820//-------------------------------------------------------------------
821// GPIO PINS
822//-------------------------------------------------------------------
823// Implemented in GPIO.cpp
824//-------------------------------------------------------------------
825
831struct GPIO
832{
833public:
840 GPIO(int pin)
841 {
842 if (pin < 0)
843 {
844 // Unspecified
845 _pin = -1;
846 return;
847 }
848
849 if (!GPIO_IS_VALID_GPIO(pin))
850 throw gpio_error(pin, "Does not exist");
851 bool reserved = false;
852#if defined(CONFIG_IDF_TARGET_ESP32)
853 reserved = (pin >= GPIO_NUM_6) && (pin <= GPIO_NUM_11); // Flash
854 reserved = reserved ||
855 ((pin >= GPIO_NUM_16) && (pin <= GPIO_NUM_17) && psramFound()); // PSRAM
856
857 // reserved = reserved || (pin == GPIO_NUM_1) || (pin == GPIO_NUM_3); // Serial port
858#elif defined(CONFIG_IDF_TARGET_ESP32S2)
859// Not sure:
860// reserved = (pin >= GPIO_NUM_22) && (pin <= GPIO_NUM_32) && (pin != GPIO_NUM_26);
861#elif defined(CONFIG_IDF_TARGET_ESP32S3)
862 reserved = ((pin >= GPIO_NUM_26) && (pin <= GPIO_NUM_32)); // Flash
863 reserved = reserved ||
864 ((pin >= GPIO_NUM_35) && (pin <= GPIO_NUM_37) && psramFound()); // PSRAM
865
866 // reserved = reserved || (pin == GPIO_NUM_43) || (pin == GPIO_NUM_44); // Serial port
867#elif defined(CONFIG_IDF_TARGET_ESP32C3)
868 reserved = (pin >= GPIO_NUM_11) && (pin <= GPIO_NUM_17);
869
870 // reserved = reserved || (pin == GPIO_NUM_20) || (pin == GPIO_NUM_21); // Serial port
871#elif CD_CI
872 reserved = (pin == TEST_RESERVED_GPIO);
873#endif
874 if (reserved)
875 throw gpio_error(pin, "Reserved for SPI FLASH, PSRAM or otherwise NOT USABLE");
876 _pin = pin;
877 }
878
883 GPIO() { _pin = -1; }
884
890 GPIO(UNSPECIFIED value) : GPIO() {}
891
897 operator int() const { return _pin; }
898
904 GPIO(const GPIO &instance) { _pin = instance._pin; }
905
913 inline bool operator==(const UNSPECIFIED value) const { return _pin < 0; }
914
922 inline bool operator!=(const UNSPECIFIED value) const { return _pin >= 0; }
923
925
926 inline bool operator!=(const GPIO value) const { return (_pin != value._pin); }
927 inline bool operator==(const GPIO value) const { return (_pin == value._pin); }
928 inline bool operator<(const GPIO value) const { return (_pin < value._pin); }
929
931
937 void reserve() const
938 {
939 abortIfUnspecified();
940 if (reservedPins.find(_pin) != reservedPins.end())
941 throw gpio_error(_pin, "Already in use");
942 else
943 reservedPins.insert(_pin);
944 }
945
950 void grant() const
951 {
952 abortIfUnspecified();
953 reservedPins.insert(_pin);
954 }
955
962 {
963 if (_pin < 0)
964 throw gpio_error(_pin, "Is unspecified but required");
965 }
966
967#if CD_CI
968 static void clearReservations()
969 {
970 reservedPins.clear();
971 }
972#endif
973
974private:
975 inline static ::std::set<int> reservedPins{};
976
977protected:
979 int _pin;
980};
981
986struct OutputGPIO : public GPIO
987{
988public:
994 OutputGPIO(int pin) : GPIO(pin)
995 {
996 if ((pin >= 0) && !GPIO_IS_VALID_OUTPUT_GPIO(pin))
997 throw gpio_error(pin, "Not output-capable");
998 }
1002 OutputGPIO(UNSPECIFIED value) : GPIO(value) {}
1003};
1004
1009struct InputGPIO : public GPIO
1010{
1011public:
1013 InputGPIO() : GPIO() {};
1019 InputGPIO(int pin) : GPIO(pin) {}
1021 InputGPIO(UNSPECIFIED value) : GPIO(value) {}
1022};
1023
1028struct ADC_GPIO : public InputGPIO
1029{
1030public:
1033
1039 ADC_GPIO(int pin) : InputGPIO(pin) {}
1040
1046 ADC_GPIO(UNSPECIFIED value) : InputGPIO(value) {}
1047};
1048
1053struct RTC_GPIO : public InputGPIO
1054{
1055public:
1061 RTC_GPIO(int pin) : InputGPIO(pin)
1062 {
1063 if ((pin >= 0) && !GPIO_IS_VALID_RTC_GPIO(pin))
1064 throw gpio_error(pin, "Not RTC-capable");
1065 }
1066};
1067
1068//-------------------------------------------------------------------
1069// GPIO pin collections
1070//-------------------------------------------------------------------
1071
1073typedef std::set<GPIO> GPIOCollection;
1075typedef std::set<InputGPIO> InputGPIOCollection;
1077typedef std::set<OutputGPIO> OutputGPIOCollection;
1078
1079//-------------------------------------------------------------------
1080// I2C
1081//-------------------------------------------------------------------
1082
1087#if CONFIG_IDF_TARGET_ESP32C3
1088// The ESP32-C3 does not have a secondary bus
1089enum class I2CBus
1090{
1091 PRIMARY = 0,
1092 SECONDARY = 0
1093};
1094#else
1095enum class I2CBus
1096{
1097 PRIMARY = 0,
1098 SECONDARY
1099};
1100#endif
1101
1102//-------------------------------------------------------------------
1103// Power latch
1104//-------------------------------------------------------------------
1105
1110enum class PowerLatchMode : uint8_t
1111{
1118};
1119
1120//-------------------------------------------------------------------
1121// Connectivity
1122//-------------------------------------------------------------------
1123
1125enum class Connectivity : uint8_t
1126{
1128 USB_BLE = 0,
1132 USB = 2,
1134 BLE = 3,
1136 DUMMY = 4,
1139};
1140
1141//-------------------------------------------------------------------
1142// LED strips
1143//-------------------------------------------------------------------
1144
1149enum class PixelGroup
1150{
1152 GRP_TELEMETRY = 0,
1157};
1158
1163enum class PixelDriver
1164{
1166 WS2811 = 0,
1168 WS2812,
1170 WS2815,
1172 SK6812,
1174 UCS1903,
1176 APA106
1177};
1178
1179//-------------------------------------------------------------------
1180// Telemetry data
1181//-------------------------------------------------------------------
1182
1187typedef struct
1188{
1193 uint32_t frameID;
1198 struct
1199 {
1201 char gear = ' ';
1203 uint16_t rpm = 0;
1205 uint8_t rpmPercent = 0;
1207 uint8_t shiftLight1 = 0;
1209 uint8_t shiftLight2 = 0;
1211 bool revLimiter = false;
1213 bool engineStarted = false;
1215 uint16_t speed = 0;
1216 } powertrain;
1221 struct
1222 {
1224 bool absEngaged = false;
1226 bool tcEngaged = false;
1228 bool drsEngaged = false;
1230 bool pitLimiter = false;
1232 bool lowFuelAlert = false;
1234 uint8_t absLevel = 0;
1236 uint8_t tcLevel = 0;
1238 uint8_t tcCut = 0;
1240 uint8_t brakeBias = 0;
1241 } ecu;
1246 struct
1247 {
1248 bool blackFlag = false;
1249 bool blueFlag = false;
1250 bool checkeredFlag = false;
1251 bool greenFlag = false;
1252 bool orangeFlag = false;
1253 bool whiteFlag = false;
1254 bool yellowFlag = false;
1256 uint16_t remainingLaps = 0;
1258 uint16_t remainingMinutes = 0;
1259 } raceControl;
1264 struct
1265 {
1267 uint8_t relativeTurboPressure = 0;
1269 float absoluteTurboPressure = 0.0;
1271 uint16_t waterTemperature = 0;
1273 float oilPressure = 0.0;
1275 uint16_t oilTemperature = 0;
1277 uint8_t relativeRemainingFuel = 0;
1279 uint16_t absoluteRemainingFuel = 0;
1280 } gauges;
1286 struct
1287 {
1289 uint16_t tireTemp[4];
1291 float tirePressure[4];
1293 uint16_t brakeTemp[4];
1295 uint8_t wearPercentage[4];
1296 } wheels;
1298
1299//-------------------------------------------------------------------
1300// Pixel format
1301//-------------------------------------------------------------------
1302
1307enum class PixelFormat : unsigned char
1308{
1310 RGB = 0,
1312 RBG,
1314 GRB,
1316 GBR,
1318 BRG,
1320 BGR
1321};
1322
1323//-------------------------------------------------------------------
1324// Pixels
1325//-------------------------------------------------------------------
1326
1331struct Pixel
1332{
1334 uint8_t blue;
1336 uint8_t green;
1338 uint8_t red;
1339
1345 operator uint32_t() const noexcept
1346 {
1347 return (blue) | (green << 8) | (red << 16);
1348 }
1349
1355 operator int() const noexcept
1356 {
1357 return (blue) | (green << 8) | (red << 16);
1358 }
1359
1365 Pixel(uint32_t packedRGB) noexcept
1366 {
1367 red = packedRGB >> 16;
1368 green = packedRGB >> 8;
1369 blue = packedRGB;
1370 }
1371
1376 Pixel() noexcept
1377 {
1378 red = 0;
1379 green = 0;
1380 blue = 0;
1381 }
1382
1385 Pixel(const Pixel &source) = default;
1386
1389 Pixel(Pixel &&source) = default;
1390
1397 Pixel &operator=(uint32_t packedRGB) noexcept
1398 {
1399 red = packedRGB >> 16;
1400 green = packedRGB >> 8;
1401 blue = packedRGB;
1402 return *this;
1403 }
1404
1408 Pixel &operator=(const Pixel &source) = default;
1409
1413 Pixel &operator=(Pixel &&source) = default;
1414
1422 bool operator==(uint32_t packedRGB) const noexcept
1423 {
1424 return (packedRGB == static_cast<uint32_t>(*this));
1425 }
1426
1434 bool operator==(int packedRGB) const noexcept
1435 {
1436 return (packedRGB == static_cast<int>(*this));
1437 }
1438
1446 bool operator==(const Pixel &other) const noexcept
1447 {
1448 return (red == other.red) &&
1449 (blue == other.blue) &&
1450 (green == other.green);
1451 }
1452
1460 bool operator!=(uint32_t packedRGB) const noexcept
1461 {
1462 return (packedRGB != static_cast<uint32_t>(*this));
1463 }
1464
1472 bool operator!=(int packedRGB) const noexcept
1473 {
1474 return (packedRGB != static_cast<int>(*this));
1475 }
1476
1484 bool operator!=(const Pixel &other) const noexcept
1485 {
1486 return (red != other.red) ||
1487 (blue != other.blue) ||
1488 (green != other.green);
1489 }
1490
1497 uint8_t byte0(PixelFormat format) const noexcept
1498 {
1499 switch (format)
1500 {
1501 case PixelFormat::BGR:
1502 [[fallthrough]];
1503 case PixelFormat::BRG:
1504 return blue;
1505 case PixelFormat::GBR:
1506 [[fallthrough]];
1507 case PixelFormat::GRB:
1508 return green;
1509 case PixelFormat::RBG:
1510 [[fallthrough]];
1511 case PixelFormat::RGB:
1512 return red;
1513 }
1514 return 0;
1515 }
1516
1523 uint8_t byte1(PixelFormat format) const noexcept
1524 {
1525 switch (format)
1526 {
1527 case PixelFormat::RBG:
1528 [[fallthrough]];
1529 case PixelFormat::GBR:
1530 return blue;
1531 case PixelFormat::BGR:
1532 [[fallthrough]];
1533 case PixelFormat::RGB:
1534 return green;
1535 case PixelFormat::BRG:
1536 [[fallthrough]];
1537 case PixelFormat::GRB:
1538 return red;
1539 }
1540 return 0;
1541 }
1542
1549 uint8_t byte2(PixelFormat format) const noexcept
1550 {
1551 switch (format)
1552 {
1553 case PixelFormat::GRB:
1554 [[fallthrough]];
1555 case PixelFormat::RGB:
1556 return blue;
1557 case PixelFormat::BRG:
1558 [[fallthrough]];
1559 case PixelFormat::RBG:
1560 return green;
1561 case PixelFormat::GBR:
1562 [[fallthrough]];
1563 case PixelFormat::BGR:
1564 return red;
1565 }
1566 return 0;
1567 }
1568}; // Pixel
1569
1570static_assert(sizeof(Pixel) == 3);
1571
1572//-------------------------------------------------------------------
1573// User interface
1574//-------------------------------------------------------------------
1575
1582{
1583protected:
1595 uint32_t frameTimer(
1596 uint32_t &timerVariable,
1597 uint32_t elapsedTimeMs,
1598 uint32_t timeLimitMs)
1599 {
1600 timerVariable += elapsedTimeMs;
1601 uint32_t result = timerVariable / timeLimitMs;
1602 timerVariable %= timeLimitMs;
1603 return result;
1604 };
1605
1606public:
1608 bool requiresPowertrainTelemetry = false;
1610 bool requiresECUTelemetry = false;
1612 bool requiresRaceControlTelemetry = false;
1614 bool requiresGaugeTelemetry = false;
1616 bool requiresWheelTelemetry = false;
1617
1618 // Non copyable
1619
1620 AbstractUserInterface() = default;
1622 AbstractUserInterface &operator=(const AbstractUserInterface &) = delete;
1623
1624 virtual ~AbstractUserInterface() {}
1625
1626public:
1634 virtual uint8_t getMaxFPS() { return 0; }
1635
1647 virtual uint16_t getStackSize() { return 0; }
1648
1653 virtual void onStart() {};
1654
1677 virtual void onTelemetryData(const TelemetryData *pTelemetryData) {};
1678
1690 virtual void serveSingleFrame(uint32_t elapsedMs) {};
1691
1698 virtual void onBitePoint(uint8_t bitePoint) {};
1699
1704 virtual void onConnected() {};
1705
1710 virtual void onBLEdiscovering() {};
1711
1718 virtual void onLowBattery() {};
1719
1724 virtual void onSaveSettings() {};
1725
1731 virtual void onUserInput(uint8_t inputNumber) {};
1732
1740 virtual void shutdown() {};
1741};
1742
1743//-------------------------------------------------------------------
1744
1751{
1752private:
1753 virtual void onStart() override;
1754 virtual void onBitePoint(uint8_t bitePoint) override;
1755 virtual void onConnected() override;
1756 virtual void onBLEdiscovering() override;
1757 virtual void onLowBattery() override;
1758 virtual void onSaveSettings() override;
1759 virtual void serveSingleFrame(uint32_t elapsedMs) override {};
1760 virtual uint8_t getMaxFPS() override { return 0; }
1761 virtual void shutdown() override {};
1762
1763protected:
1764 // Singleton pattern
1765
1768
1769 // For descendant classes
1770
1772 ::std::vector<Pixel> telemetry_pixel{};
1773
1775 ::std::vector<Pixel> backlit_button_pixel{};
1776
1778 ::std::vector<Pixel> individual_pixel{};
1779
1787 bool notConnectedYet = true;
1788
1794 void show(PixelGroup group) noexcept;
1795
1800 void show() noexcept;
1801
1807 static void reset() noexcept;
1808
1816 static uint8_t getPixelCount(PixelGroup group) noexcept;
1817
1829 bool renderBatteryLevel(uint32_t barColor = 0x00ACFA70);
1830
1831public:
1837 static PixelControlNotification *getInstance()
1838 {
1839 static PixelControlNotification *_instance = nullptr;
1840 if (!_instance)
1841 _instance = new PixelControlNotification();
1842 return _instance;
1843 }
1844
1845public:
1847 void operator=(const PixelControlNotification &) = delete;
1848
1853 virtual void pixelControl_OnStart();
1854
1860 virtual void pixelControl_OnBitePoint(uint8_t bitePoint);
1861
1868
1875
1881
1889};
constexpr bool operator!=(uint128_t a, uint128_t b)
Check inequality.
constexpr uint128_t operator>>(const uint128_t &source, ::std::size_t n) noexcept
Shift right.
constexpr uint128_t operator~(uint128_t a) noexcept
Bitwise negation.
#define GPIO_IS_VALID_RTC_GPIO(pin)
Validation of RTC GPIO pins.
PixelGroup
Available RGB LED groups for pixel control.
@ GRP_INDIVIDUAL
Individual leds group.
@ GRP_BUTTONS
Buttons lighting group.
@ GRP_TELEMETRY
Telemetry leds group.
Connectivity
Connectivity choice.
@ USB_BLE_EXCLUSIVE
Combined USB and BLE connectivity with forced connection drop.
@ USB
USB connectivity only, if available.
@ _DEFAULT
Default connectivity.
@ USB_BLE
Combined USB and BLE connectivity if available.
@ BLE
BLE connectivity only, if available.
@ DUMMY
No connectivity at all (for troubleshooting)
UNSPECIFIED
Unspecified value type.
@ VALUE
Unspecified value.
I2CBus
I2C bus controller.
std::set< InputGPIO > InputGPIOCollection
Collection of input GPIOs.
constexpr uint128_t operator&(uint128_t a, uint128_t b) noexcept
Bitwise AND.
std::set< OutputGPIO > OutputGPIOCollection
Collection of output GPIOs.
int map_value(int x, int in_min, int in_max, int out_min, int out_max)
Equivalent to Arduino's map()
constexpr bool operator==(uint128_t a, uint128_t b) noexcept
Check equality.
PowerLatchMode
Supported power latch modes.
@ POWER_OFF_LOW
Power on when high voltage, power off when low voltage.
@ POWER_OFF_HIGH
Power on when low voltage, power off when high voltage.
@ POWER_OPEN_DRAIN
Power on when low voltage, power off when open drain.
PixelDriver
Pixel driver.
@ UCS1903
UCS1903 driver.
@ SK6812
SK6812 driver.
@ WS2812
WS2812 family.
@ APA106
APA106 driver.
@ WS2815
WS2815 family.
@ WS2811
WS2811 driver.
PixelFormat
Byte order of pixel data starting with the least significant byte.
@ RBG
Red-blue-green.
@ BGR
Blue-green-red.
@ BRG
Blue-red-green.
@ GRB
Green-red-blue.
@ RGB
Red-green-blue.
@ GBR
Green-blue-red.
std::set< GPIO > GPIOCollection
Collection of GPIOs.
constexpr uint128_t operator|(uint128_t a, uint128_t b) noexcept
Bitwise OR.
constexpr uint128_t operator<<(const uint128_t &source, ::std::size_t n) noexcept
Shift left.
constexpr uint128_t operator^(uint128_t a, uint128_t b) noexcept
Bitwise XOR.
Abstract interface for notifications and telemetry display.
virtual void shutdown()
Cut power to the UI hardware.
virtual void onStart()
Called just once after initialization.
virtual uint8_t getMaxFPS()
Get the maximum FPS supported by the underlying hardware.
virtual void onLowBattery()
Notify low battery.
virtual void onConnected()
Notify device is connected.
virtual void onBLEdiscovering()
Notify device is in discovery mode.
virtual uint16_t getStackSize()
Get the stack size required by this user interface.
virtual void onSaveSettings()
Notify that user settings have been saved to flash memory.
uint32_t frameTimer(uint32_t &timerVariable, uint32_t elapsedTimeMs, uint32_t timeLimitMs)
Simple timer.
virtual void serveSingleFrame(uint32_t elapsedMs)
Draw a single frame.
virtual void onUserInput(uint8_t inputNumber)
Notify user input.
virtual void onTelemetryData(const TelemetryData *pTelemetryData)
Notify new telemetry data.
virtual void onBitePoint(uint8_t bitePoint)
Notify a change in the current bite point.
Notifications using pixel control.
void show() noexcept
Show pixels all at once in all groups.
virtual void pixelControl_OnConnected()
Notify device is connected.
PixelControlNotification()
Initialize.
virtual void pixelControl_OnBitePoint(uint8_t bitePoint)
Notify a change in current bite point.
virtual void pixelControl_OnLowBattery()
Notify low battery.
void show(PixelGroup group) noexcept
Show pixels all at once in a specific group.
virtual void pixelControl_OnSaveSettings()
Notify that user settings have been saved to flash memory.
virtual void pixelControl_OnBLEdiscovering()
Notify device is in discovery mode.
virtual void pixelControl_OnStart()
Called just once after initialization.
Exception for empty input number specifications.
empty_input_number_set(const std::string &hardware)
Construct a new empty_input_number_set exception.
Exception for invalid GPIO pin numbers.
gpio_error(uint8_t value, const std::string &reason)
Construct a new gpio_error exception.
Exception for invalid input numbers.
invalid_input_number()
Construct a new invalid input number object for unspecified input numbers.
invalid_input_number(uint8_t value)
Construct a new invalid_input_number exception.
Exception for unknown input numbers.
unknown_input_number(const std::string &usage)
Construct a new unknown_input_number exception.
ADC-capable GPIO pin number.
ADC_GPIO(UNSPECIFIED value)
Create a "not connected" ADC GPIO.
ADC_GPIO(int pin)
Create an ADC GPIO connected to a pin number.
ADC_GPIO()
Create a "not connected" ADC GPIO.
GPIO pin number.
bool operator==(const UNSPECIFIED value) const
Check if "not connected".
void reserve() const
Reserve this GPIO for exclusive use.
GPIO(int pin)
Assign a pin number.
GPIO(UNSPECIFIED value)
Assign a "not connected" value.
int _pin
Assigned pin number.
void abortIfUnspecified() const
Throw an exception if unspecified.
void grant() const
Grant this GPIO for non-exclusive use.
GPIO(const GPIO &instance)
Copy another GPIO instance.
bool operator!=(const UNSPECIFIED value) const
Check if a pin number was assigned.
GPIO()
Create a GPIO as "not connected".
Input-capable GPIO pin number.
InputGPIO(UNSPECIFIED value)
Create a "not connected" input GPIO.
InputGPIO(int pin)
Create an input GPIO.
InputGPIO()
Create a "not connected" input GPIO.
Combination of input numbers.
constexpr InputNumberCombination(InputNumberCombination &&) noexcept=default
Move constructor (default)
constexpr InputNumberCombination()
Create an empty combination of input numbers.
constexpr InputNumberCombination(uint128_t &&from)
Create from a 128-bit bitmap.
constexpr InputNumberCombination(const InputNumberCombination &) noexcept=default
Copy constructor (default)
constexpr InputNumberCombination(const uint128_t &from)
Create from a 128-bit bitmap.
constexpr uint8_t size() const noexcept
Get the count of input numbers in the combination.
constexpr InputNumberCombination(std::initializer_list< InputNumber > items) noexcept
Create a combination of input numbers.
Firmware-defined input numbers in the range [0,127] or unspecified.
static void book(uint8_t inputNumber)
Unbook.
constexpr InputNumber(uint8_t value)
Cast an integer to a input number.
constexpr InputNumber & operator=(InputNumber &&number)=default
Move-assignment (default)
constexpr InputNumber(InputNumber &&number)=default
Move constructor (default)
constexpr InputNumber(UNSPECIFIED value) noexcept
Assign an unspecified value.
constexpr InputNumber & operator=(const InputNumber &number)=default
Copy-assignment (default)
static void bookAll()
Book all input numbers as in use (for testing)
void unbook() const
Unbook.
void book() const
Book as in use.
static void unbook(uint8_t inputNumber)
Book an input number as in use.
bool constexpr operator==(const UNSPECIFIED value) const
Check if this input number is unspecified.
static bool booked(InputNumber inputNumber)
Check if an input number is booked.
static uint128_t booked()
Get a bitmap of all booked input numbers.
bool constexpr operator!=(const UNSPECIFIED value) const noexcept
Check if this input number was specified.
constexpr InputNumber() noexcept
Construct an unspecified input number.
constexpr InputNumber(const InputNumber &number)=default
Copy constructor (default)
static bool booked(uint8_t inputNumber)
Check if an input number is booked.
Output-capable GPIO pin number.
OutputGPIO()
Create a "not connected" GPIO.
OutputGPIO(int pin)
Create a GPIO.
OutputGPIO(UNSPECIFIED value)
Create a "not connected" GPIO.
Pixel in 3-byte packed RGB format.
Pixel() noexcept
Create as a black pixel.
Pixel(Pixel &&source)=default
Move-constructor.
Pixel(uint32_t packedRGB) noexcept
Create from a packed RGB value.
uint8_t byte2(PixelFormat format) const noexcept
Get the third color channel in a certain pixel format.
uint8_t blue
Blue channel.
Pixel & operator=(const Pixel &source)=default
Copy-assignment.
Pixel & operator=(Pixel &&source)=default
Move-assignment.
uint8_t green
Green channel.
bool operator!=(int packedRGB) const noexcept
Compare to a packed RGB color.
bool operator==(int packedRGB) const noexcept
Compare to a packed RGB color.
bool operator==(uint32_t packedRGB) const noexcept
Compare to a packed RGB color.
bool operator!=(uint32_t packedRGB) const noexcept
Compare to a packed RGB color.
bool operator==(const Pixel &other) const noexcept
Compare to another pixel.
bool operator!=(const Pixel &other) const noexcept
Compare to another pixel.
uint8_t red
Red channel.
uint8_t byte0(PixelFormat format) const noexcept
Get the first color channel in a certain pixel format.
uint8_t byte1(PixelFormat format) const noexcept
Get the second color channel in a certain pixel format.
Pixel(const Pixel &source)=default
Copy-constructor.
Pixel & operator=(uint32_t packedRGB) noexcept
Assign a packed RGB color.
RTC-capable GPIO pin number.
RTC_GPIO(int pin)
Create a RTC GPIO connected to a pin number.
Telemetry data.
uint32_t frameID
Identifies a telemetry frame. For internal use. Do not overwrite.
128-bit integer
static constexpr uint128_t bitmap(uint8_t n) noexcept
Get the bitmap that represents a number.
constexpr uint128_t & operator^=(const uint128_t &rhs) noexcept
Compound bitwise XOR.
constexpr uint128_t & operator&=(const uint128_t &rhs) noexcept
Compound bitwise AND.
constexpr uint128_t & operator|=(const uint128_t &rhs) noexcept
Compound bitwise OR.
uint64_t low
Least significant unsigned long long.
constexpr bool bit(uint8_t n) const noexcept
Check bit.
constexpr void set_bit(uint8_t n, bool value=true) noexcept
Set or clear a single bit.
uint64_t high
Most significant unsigned long long.
static constexpr uint128_t neg() noexcept
Get the bitwise negation of zero.