OpenSourceSimWheelESP32
Open-source wireless steering wheel/button box for ESP32 boards
Loading...
Searching...
No Matches
InternalTypes.hpp
Go to the documentation of this file.
1
12#pragma once
13
14//-------------------------------------------------------------------
15// Imports
16//-------------------------------------------------------------------
17
18#include <cstdint>
19#include <cassert>
20#include <array>
21#include <vector>
22#include <stdexcept>
23#include <semaphore>
24#include <chrono>
25#include <optional>
26
27#if !CD_CI
29#define PRIVATE private
30#include "esp_task_wdt.h" // For esp_task_wdt_reset()
32#define PROTECTED protected
33#else
35#define PRIVATE public
37#define PROTECTED public
38#endif
39
40//-------------------------------------------------------------------
41// Testing
42//-------------------------------------------------------------------
43
49{
51 uint64_t state = 0ULL;
53 uint64_t mask = ~(0ULL);
55 uint8_t leftAxis = 0;
57 uint8_t rightAxis = 0;
60
66 void press(uint8_t n)
67 {
68 uint64_t bmp = (1ULL << n);
69 state = state | bmp;
70 }
71
77 void release(uint8_t n)
78 {
79 uint64_t bmp = (1ULL << n);
80 state = state & ~bmp;
81 }
82
87 void clear()
88 {
89 state = 0ULL;
90 leftAxis = 0;
91 rightAxis = 0;
92 }
93
94 FakeInput() {}
95 ~FakeInput() {}
96};
97
98//-------------------------------------------------------------------
99// Input bitmaps
100//-------------------------------------------------------------------
101
112#define BITMASK(count, first) \
113 ~(((1ULL << static_cast<uint64_t>(count)) - 1ULL) \
114 << static_cast<uint64_t>(first))
115
120#define NBITMASK(count, first) \
121 (((1ULL << static_cast<uint64_t>(count)) - 1ULL) \
122 << static_cast<uint64_t>(first))
123
124//-------------------------------------------------------------------
125// Device capabilities
126//-------------------------------------------------------------------
127
132enum class DeviceCapability : uint8_t
133{
135 CLUTCH_BUTTON = 0,
137 CLUTCH_ANALOG = 1,
139 ALT = 2,
141 DPAD = 3,
143 BATTERY = 4,
149 TELEMETRY_ECU = 7,
155 ROTARY_ENCODERS = 10,
156 _MAX_VALUE = ROTARY_ENCODERS
157};
158
164{
165public:
172 static void setFlag(DeviceCapability capability, bool setOrClear = true)
173 {
174 if (setOrClear)
175 _flags |= (1 << static_cast<uint8_t>(capability));
176 else
177 _flags &= ~(1 << static_cast<uint8_t>(capability));
178 }
179
187 static bool hasFlag(DeviceCapability capability)
188 {
189 return _flags & (1 << static_cast<uint8_t>(capability));
190 }
191
197 static uint16_t getFlags() { return _flags; }
198
199private:
200 inline static uint16_t _flags = 0;
201};
202
203//-------------------------------------------------------------------
204// Clutch
205//-------------------------------------------------------------------
206
211enum class ClutchWorkingMode : uint8_t
212{
214 CLUTCH = 0,
216 AXIS,
218 ALT,
220 BUTTON,
225 _MAX_VALUE = LAUNCH_CONTROL_MASTER_RIGHT,
226 _DEFAULT_VALUE = CLUTCH
227};
228
230#define CLUTCH_NONE_VALUE 0
232#define CLUTCH_FULL_VALUE 254
234#define CLUTCH_DEFAULT_VALUE 127
236#define CLUTCH_1_4_VALUE 64
238#define CLUTCH_3_4_VALUE 192
240#define CLUTCH_INVALID_VALUE 255
241
242//-------------------------------------------------------------------
243// ALT BUTTONS
244//-------------------------------------------------------------------
245
250enum class AltButtonsWorkingMode : uint8_t
251{
253 Regular = 0,
255 ALT,
256 _MAX_VALUE = ALT,
257 _DEFAULT_VALUE = ALT
258};
259
260//-------------------------------------------------------------------
261// Rotary encoder
262//-------------------------------------------------------------------
263
268enum class PulseWidthMultiplier : uint8_t
269{
270 X1 = 1,
271 X2,
272 X3,
273 X4,
274 X5,
275 X6,
276 _MAX_VALUE = X6,
277 _DEFAULT_VALUE = X2
278};
279
280//-------------------------------------------------------------------
281// DPAD
282//-------------------------------------------------------------------
283
288enum class DPadWorkingMode : uint8_t
289{
291 Regular = 0,
294 _MAX_VALUE = Navigation,
295 _DEFAULT_VALUE = Navigation
296};
297
298//-------------------------------------------------------------------
299// Global firmware parameters
300//-------------------------------------------------------------------
301
306#define INPUT_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
307
308//-------------------------------------------------------------------
309// Queues
310//-------------------------------------------------------------------
311
320{
321public:
328 void enqueue(bool value)
329 {
330 uint8_t bqTailNext = bqTail;
331 incDataPointer(bqTailNext);
332 if (bqTailNext != bqHead)
333 {
334 // Queue not full
335 uint64_t aux = (1ULL << bqTail);
336 bitsQueue &= (~aux);
337 if (value)
338 bitsQueue |= aux;
339 bqTail = bqTailNext;
340 } // else queue full, overflow
341 }
342
350 bool dequeue(bool &value)
351 {
352 bool isNotEmpty = (bqHead != bqTail);
353 if (isNotEmpty)
354 {
355 uint64_t bitState = (1ULL << bqHead) & bitsQueue;
356 value = (bitState != 0ULL);
357 incDataPointer(bqHead);
358 }
359 return isNotEmpty;
360 }
361
363
364 PRIVATE : uint64_t bitsQueue = 0ULL;
365 uint8_t bqHead = 0; // "pointer" (short of) to head
366 uint8_t bqTail = 0; // "pointer" to tail
367
368 inline static void incDataPointer(uint8_t &pointer)
369 {
370 pointer = (pointer + 1) % 64;
371 };
372
374};
375
376//-------------------------------------------------------------------
377// Inputs-InputHub decoupling
378//-------------------------------------------------------------------
379
385{
394};
395
397#define MAX_DECOUPLING_EVENT_COUNT 64
398
399//-------------------------------------------------------------------
400// Battery Management
401//-------------------------------------------------------------------
402
405{
406public:
408 std::optional<uint8_t> stateOfCharge{};
410 std::optional<bool> isCharging{};
412 std::optional<bool> isBatteryPresent{};
414 std::optional<bool> usingExternalPower{};
415
423 constexpr bool operator==(const BatteryStatus &other) const noexcept
424 {
425 return (stateOfCharge == other.stateOfCharge) &&
426 (isCharging == other.isCharging) &&
427 (isBatteryPresent == other.isBatteryPresent) &&
428 (usingExternalPower == other.usingExternalPower);
429 }
430
435 inline void reset() noexcept
436 {
437 stateOfCharge.reset();
438 isCharging.reset();
439 isBatteryPresent.reset();
440 usingExternalPower.reset();
441 }
442};
443
444#pragma pack(push, 1)
445
449{
451 unsigned int flag_id_present : 1 = 1;
453 unsigned int flag_battery_level_present : 1 = 1;
455 unsigned int flag_additional_status_present : 1 = 1;
457 unsigned int flag_reserved : 5 = 0;
458
459 // End of byte 0
460
462 unsigned int ps_battery_present : 1 = 0;
464 unsigned int ps_wired_ext_power : 2 = 1;
466 unsigned int ps_wireless_ext_power : 2 = 0;
468 unsigned int ps_battery_charge_state : 2 = 0;
470 unsigned int ps_battery_charge_level : 2 = 1;
472 unsigned int ps_charging_type : 3 = 0;
474 unsigned int ps_fault_reason : 3 = 0;
476 unsigned int ps_reserved : 1 = 0;
477
478 // End of bytes 1-2
479
481 uint16_t id = 0x106;
482
483 // End of bytes 3-4
484
486 uint8_t battery_level = 100;
487
488 // End of byte 5
489
491 unsigned int as_service_required : 1 = 0;
493 unsigned int as_battery_fault : 2 = 0;
495 unsigned int as_reserved : 5 = 0;
496
497 // End of byte 6
498};
499
500// For unknown reasons, the x86 compiler ignores the pragma pack directive
501#if !CD_CI
502static_assert(
503 sizeof(BatteryStatusChrData) == 7,
504 "Wrong size of BatteryStatusChrData (check struct packaging)");
505#endif
506
507#pragma pack(pop)
508
509//-------------------------------------------------------------------
510// Internal events
511//-------------------------------------------------------------------
512
549
556enum class UserSetting : uint8_t
557{
558 ALL = 0,
559 AXIS_CALIBRATION,
560 AXIS_POLARITY,
561 PULSE_WIDTH,
562 SECURITY_LOCK,
563 BITE_POINT,
564 CLUTCH_WORKING_MODE,
565 ALT_WORKING_MODE,
566 DPAD_WORKING_MODE,
567 INPUT_MAP,
568 CUSTOM_HARDWARE_ID,
569 BATTERY_AUTO_CALIBRATION,
570 BATTERY_CALIBRATION_DATA,
571 _MAX_VALUE = BATTERY_CALIBRATION_DATA
572};
573
582template <InternalEventType eventType, typename... _Args>
584{
586 typedef void (*Callback)(_Args...);
587
596 static void subscribe(Callback callback)
597 {
598 if (callback != nullptr)
599 _callbacks.push_back(callback);
600 }
601
607 static void notify(_Args... __args)
608 {
609 for (auto callback : _callbacks)
610 {
611#if !CD_CI
612 esp_task_wdt_reset();
613#endif
614 callback(std::forward<_Args>(__args)...);
615 }
616 }
617
618private:
619 inline static std::vector<Callback> _callbacks = {};
620};
621
627template <InternalEventType eventType>
628struct InternalEvent<eventType, void>
629{
631 typedef void (*Callback)();
632
638 static void subscribe(Callback callback)
639 {
640 if (callback != nullptr)
641 _callbacks.push_back(callback);
642 }
643
648 static void notify()
649 {
650 for (auto callback : _callbacks)
651 callback();
652 }
653
658 static void clearSubscriptions()
659 {
660 _callbacks.clear();
661 }
662
663private:
664 inline static std::vector<Callback> _callbacks = {};
665};
666
672
678
685
691
697
704
709typedef InternalEvent<
713
720
727
732typedef InternalEvent<
736
743
748typedef InternalEvent<
750 const BatteryStatus &>
752
759
766
767//-------------------------------------------------------------------
768// Automatic shutdown
769//-------------------------------------------------------------------
770
775#define AUTO_POWER_OFF_DELAY_SECS 60
776
777//-------------------------------------------------------------------
778// Simple commands
779//-------------------------------------------------------------------
780
InternalEvent< InternalEventType::SaveSetting, UserSetting > SaveSetting
Request to save a user setting.
SimpleCommand
Simple commands accepted from a feature HID report.
@ CMD_SHOW_PIXELS
Display all pixels in all pixel groups.
@ CMD_SAVE_NOW
Save all user settings to flash memory immediately.
@ CMD_AXIS_RECALIBRATE
Recalibrate analog axes (if any)
@ CMD_RESERVED
Not a command, reserved to avoid mistakes.
@ CMD_REVERSE_LEFT_AXIS
Reverse left axis (if any)
@ CMD_RESET_PIXELS
Turn off all pixels in all groups.
@ CMD_BATT_RECALIBRATE
Restart battery auto-calibration.
@ CMD_REVERSE_RIGHT_AXIS
Reverse right axis (if any)
@ CMD_RESET_BUTTONS_MAP
Reset buttons map to factory defaults.
InternalEventType
Available internal event types.
@ LowBattery
The system is in a low battery state (repeated at timed intervals)
@ Shutdown
Sytem shutdown.
@ Connected
Device connected to a host computer.
@ NewBatteryStatus
Change in battery status or battery level.
@ AltButtonsWorkingMode
The ALT buttons working mode has changed.
@ BitePoint
The bite point has changed.
@ SettingsSaved
User settings were saved.
@ Start
System startup.
@ PulseWidthMultiplier
The pulse width multiplier has changed.
@ Disconnected
Discovery mode started.
InternalEvent< InternalEventType::SettingsSaved, void > OnSettingsSaved
Save event.
InternalEvent< InternalEventType::Shutdown, void > OnShutdown
The system is about to shutdown.
InternalEvent< InternalEventType::NewBatteryStatus, const BatteryStatus & > OnBatteryStatus
New battery level (state of charge) or battery status.
InternalEvent< InternalEventType::DPadWorkingMode, void > OnDPadWorkingMode
New DPAD working mode.
InternalEvent< InternalEventType::Connected, void > OnConnected
Host connection.
InternalEvent< InternalEventType::Start, void > OnStart
System startup.
InternalEvent< InternalEventType::ClutchWorkingMode, ClutchWorkingMode > OnClutchWorkingMode
New clutch working mode.
#define PRIVATE
For tesing.
ClutchWorkingMode
User-selected working mode of the clutch paddles.
@ LAUNCH_CONTROL_MASTER_LEFT
Launch control (left paddle is master)
@ CLUTCH
F1-Style clutch. Must be the first in the enum: do not change.
@ BUTTON
Regular buttons.
@ AXIS
Independent axes.
@ LAUNCH_CONTROL_MASTER_RIGHT
Launch control (right paddle is master)
PulseWidthMultiplier
User-selected pulse width multiplier.
AltButtonsWorkingMode
User-selected working mode of "ALT" buttons.
@ Regular
Regular button.
InternalEvent< InternalEventType::Disconnected, void > OnDisconnected
No host connection.
InternalEvent< InternalEventType::LowBattery, void > OnLowBattery
Notified when a low battery condition is detected.
InternalEvent< InternalEventType::PulseWidthMultiplier, PulseWidthMultiplier > OnPulseWidthMultiplier
New pulse width multiplier.
InternalEvent< InternalEventType::BitePoint, uint8_t > OnBitePoint
New bite point.
DeviceCapability
Enumeration of device capabilities.
@ TELEMETRY_POWERTRAIN
Able to display powertrain telemetry data.
@ DPAD
Has a directional pad.
@ CLUTCH_BUTTON
Has digital clutch paddles (switches)
@ BATTERY_CALIBRATION_AVAILABLE
Has battery calibration data.
@ TELEMETRY_RACE_CONTROL
Able to display race control telemetry data.
@ BATTERY
Battery-operated.
@ CLUTCH_ANALOG
Has analog clutch paddles (potentiometers)
@ TELEMETRY_ECU
Able to display ECU telemetry data.
@ ROTARY_ENCODERS
Has one or more rotary encoders.
@ ALT
Has "ALT" buttons.
@ TELEMETRY_GAUGES
Able to display telemetry data for gauges.
DPadWorkingMode
User-selected working mode of directional pads.
@ Navigation
Navigation control.
InternalEvent< InternalEventType::AltButtonsWorkingMode, AltButtonsWorkingMode > OnAltButtonsWorkingMode
New ALT buttons working mode.
UserSetting
User setting to be stored in flash memory.
InternalEvent< InternalEventType::LoadSetting, UserSetting > LoadSetting
Request to load a user setting.
Queue for 61 bits.
void enqueue(bool value)
Push a bit into the queue.
bool dequeue(bool &value)
Extract a bit from the queue.
Data format for the Battery Level Status characteristic (packed)
unsigned int as_service_required
Additional status: service required.
unsigned int ps_battery_charge_level
Power state: summarized state of charge.
unsigned int flag_reserved
Flags: reserved for future use.
uint8_t battery_level
Field: Battery level.
unsigned int as_battery_fault
Additional status: battery fault status.
unsigned int flag_id_present
Flags: id field present.
unsigned int ps_wired_ext_power
Power state: is wired external power present.
unsigned int ps_fault_reason
Power state: charging fault reason.
unsigned int ps_battery_charge_state
Power state: battery charging status.
unsigned int flag_battery_level_present
Flags: battery level field present.
unsigned int as_reserved
Additional status: reserved for future use.
unsigned int ps_charging_type
Power state: charging type.
unsigned int flag_additional_status_present
Flags: additional status field present.
unsigned int ps_reserved
Power state: reserved for future use.
unsigned int ps_wireless_ext_power
Power state: is wireless external power present.
unsigned int ps_battery_present
Power state: is battery present.
Battery status.
constexpr bool operator==(const BatteryStatus &other) const noexcept
Compare for equality.
std::optional< bool > usingExternalPower
True if there is wired power.
std::optional< uint8_t > stateOfCharge
Measured battery level in the range from 0% to 100%.
void reset() noexcept
Reset to unknown.
std::optional< bool > isCharging
True if the battery is being charged.
std::optional< bool > isBatteryPresent
False if the battery is not connected.
Decoupling event.
uint8_t leftAxisValue
Position of the left axis.
uint8_t rightAxisValue
Position of the right axis.
uint64_t rawInputBitmap
Input bitmap.
uint64_t rawInputChanges
Bitmap of changes from the previous event.
Set of device capabilities.
static uint16_t getFlags()
Get all flags as a bitmap.
static void setFlag(DeviceCapability capability, bool setOrClear=true)
Clear or set a device capability.
static bool hasFlag(DeviceCapability capability)
Check if a capability is available.
Fake input specification used for testing.
uint8_t leftAxis
Left axis position.
uint8_t rightAxis
Right axis position.
void press(uint8_t n)
Simulate a button press.
void clear()
Simulate no input.
size_t recalibrationRequestCount
Count of times axis recalibration was asked.
uint64_t state
Input bitmap.
uint64_t mask
Input bitmask.
void release(uint8_t n)
Simulate a button release.
static void subscribe(Callback callback)
Subscribe to this event.
static void clearSubscriptions()
Clear subscriptions (for testing)
static void notify()
Invoke all subscribed callbacks.
Subscribable events.
void(*) Callback(_Args...)
Callback prototype.
static void notify(_Args... __args)
Invoke all subscribed callbacks.
static void subscribe(Callback callback)
Subscribe to this event.