game timers
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
#ifndef SSEGS_HPP
|
||||
#define SSEGS_HPP
|
||||
|
||||
#include <variant>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
/// A command to send to the sseg timer controller.
|
||||
struct SSegCommand {
|
||||
enum class Type {
|
||||
SetIntensity,
|
||||
EnableGameTimer,
|
||||
DisableGameTimer,
|
||||
StartGameTimer,
|
||||
StopGameTimer,
|
||||
SetGameTime,
|
||||
EnableModuleTimer,
|
||||
DisableModuleTimer,
|
||||
StartModuleTimer,
|
||||
StopModuleTimer,
|
||||
SetModuleTime,
|
||||
SetGameRaw,
|
||||
SetGameDigit,
|
||||
SetModuleRaw,
|
||||
SetModuleDigit,
|
||||
SetGameRollover,
|
||||
SetModuleRollover,
|
||||
};
|
||||
|
||||
Type type;
|
||||
std::variant<
|
||||
std::monostate, // for commands without data
|
||||
uint8_t, // SetIntensity
|
||||
int32_t, // SetGameTime, SetModuleTime
|
||||
std::array<uint8_t, 4>, // SetGameRaw, SetModuleRaw
|
||||
std::pair<uint8_t, uint8_t>, // SetGameDigit, SetModuleDigit
|
||||
bool // SetGameRollover, SetModuleRollover
|
||||
> data;
|
||||
|
||||
// Constructors for each variant
|
||||
static SSegCommand SetIntensity(uint8_t intensity) {
|
||||
return {Type::SetIntensity, intensity};
|
||||
}
|
||||
|
||||
static SSegCommand EnableGameTimer() {
|
||||
return {Type::EnableGameTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand DisableGameTimer() {
|
||||
return {Type::DisableGameTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand StartGameTimer() {
|
||||
return {Type::StartGameTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand StopGameTimer() {
|
||||
return {Type::StopGameTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand SetGameTime(int32_t time) {
|
||||
return {Type::SetGameTime, time};
|
||||
}
|
||||
|
||||
static SSegCommand EnableModuleTimer() {
|
||||
return {Type::EnableModuleTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand DisableModuleTimer() {
|
||||
return {Type::DisableModuleTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand StartModuleTimer() {
|
||||
return {Type::StartModuleTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand StopModuleTimer() {
|
||||
return {Type::StopModuleTimer, std::monostate{}};
|
||||
}
|
||||
|
||||
static SSegCommand SetModuleTime(int32_t time) {
|
||||
return {Type::SetModuleTime, time};
|
||||
}
|
||||
|
||||
static SSegCommand SetGameRaw(std::array<uint8_t, 4> raw) {
|
||||
return {Type::SetGameRaw, raw};
|
||||
}
|
||||
|
||||
static SSegCommand SetGameDigit(uint8_t digit, uint8_t value) {
|
||||
return {Type::SetGameDigit, std::make_pair(digit, value)};
|
||||
}
|
||||
|
||||
static SSegCommand SetModuleRaw(std::array<uint8_t, 4> raw) {
|
||||
return {Type::SetModuleRaw, raw};
|
||||
}
|
||||
|
||||
static SSegCommand SetModuleDigit(uint8_t digit, uint8_t value) {
|
||||
return {Type::SetModuleDigit, std::make_pair(digit, value)};
|
||||
}
|
||||
|
||||
static SSegCommand SetGameRollover(bool rollover) {
|
||||
return {Type::SetGameRollover, rollover};
|
||||
}
|
||||
|
||||
static SSegCommand SetModuleRollover(bool rollover) {
|
||||
return {Type::SetModuleRollover, rollover};
|
||||
}
|
||||
};
|
||||
|
||||
class SSegController {
|
||||
public:
|
||||
/// A hexidecimal font for the seven segment displays.
|
||||
constexpr static uint8_t FONT_HEX[16] = {
|
||||
0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101,
|
||||
0b00000111, 0b01111111, 0b01101111, 0b01110111, 0b01111100, 0b00111001, 0b01011110,
|
||||
0b01111001, 0b01110001,
|
||||
};
|
||||
/// The mask for the 'A' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_A = 0b0000'0001;
|
||||
/// The mask for the 'B' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_B = 0b0000'0010;
|
||||
/// The mask for the 'C' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_C = 0b0000'0100;
|
||||
/// The mask for the 'D' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_D = 0b0000'1000;
|
||||
/// The mask for the 'E' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_E = 0b0001'0000;
|
||||
/// The mask for the 'F' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_F = 0b0010'0000;
|
||||
/// The mask for the 'G' segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_G = 0b0100'0000;
|
||||
/// The mask for the 'DP' (decimal point) segment of the display.
|
||||
constexpr static uint8_t BIT_MASK_DP = 0b1000'0000;
|
||||
|
||||
/// Enables the game timer.
|
||||
///
|
||||
/// This "gives control" of the game timer over to the
|
||||
/// timer task.
|
||||
///
|
||||
/// This does not start the game timer, only enables it.
|
||||
static void enable_game_timer();
|
||||
|
||||
/// Disables the game timer.
|
||||
///
|
||||
/// This "takes control" of the game timer away from the
|
||||
/// timer task.
|
||||
///
|
||||
/// This also stops the timer, resets the time to 0, and clears
|
||||
/// the display.
|
||||
static void disable_game_timer();
|
||||
|
||||
/// Starts the game timer.
|
||||
///
|
||||
/// This can be called while the game timer is disabled,
|
||||
/// but the timer will not start until it is enabled.
|
||||
///
|
||||
/// Calling this while the timer is disabled can be useful
|
||||
/// if you want it to start counting right away.
|
||||
static void start_game_timer();
|
||||
|
||||
/// Stops the game timer.
|
||||
///
|
||||
/// This can be called while the game timer is disabled,
|
||||
/// but the timer only counts while it is enabled regardless.
|
||||
static void stop_game_timer();
|
||||
|
||||
/// Sets the game time.
|
||||
///
|
||||
/// This can be called even when the game timer is disabled.
|
||||
///
|
||||
/// A negative number will cause the timer to count up.
|
||||
static void set_game_time(int32_t millis);
|
||||
|
||||
/// Enables the module timer.
|
||||
///
|
||||
/// This "gives control" of the module timer over to the
|
||||
/// timer task.
|
||||
///
|
||||
/// This does not start the module timer, only enables it.
|
||||
static void enable_module_timer();
|
||||
|
||||
/// Disables the module timer.
|
||||
///
|
||||
/// This "takes control" of the module timer away from the
|
||||
/// timer task.
|
||||
///
|
||||
/// This also stops the timer, resets the time to 0, and clears
|
||||
/// the display.
|
||||
static void disable_module_timer();
|
||||
|
||||
/// Starts the module timer.
|
||||
///
|
||||
/// This can be called while the module timer is disabled,
|
||||
/// but the timer will not start until it is enabled.
|
||||
///
|
||||
/// Calling this while the timer is disabled can be useful
|
||||
/// if you want it to start counting right away.
|
||||
static void start_module_timer();
|
||||
|
||||
/// Stops the module timer.
|
||||
///
|
||||
/// This can be called while the module timer is disabled,
|
||||
/// but the timer only counts while it is enabled regardless.
|
||||
static void stop_module_timer();
|
||||
|
||||
/// Sets the module time.
|
||||
///
|
||||
/// This can be called even when the module timer is disabled.
|
||||
///
|
||||
/// A negative number will cause the timer to count up.
|
||||
static void set_module_time(int32_t millis);
|
||||
|
||||
/// Sets the game timer to the given raw segments.
|
||||
///
|
||||
/// You should ensure the game timer is disabled before
|
||||
/// calling this, otherwise, the data will be overwritten.
|
||||
static void set_game_raw(const std::array<uint8_t, 4>& segments);
|
||||
|
||||
/// Sets the game timer digit to the given raw segments.
|
||||
///
|
||||
/// You should ensure the game timer is disabled before
|
||||
/// calling this, otherwise, the data will be overwritten.
|
||||
///
|
||||
/// `digit` should be in the range 0..=3.
|
||||
static void set_game_digit_raw(uint8_t digit, uint8_t segments);
|
||||
|
||||
/// Sets the module timer to the given raw segments.
|
||||
///
|
||||
/// You should ensure the module timer is disabled before
|
||||
/// calling this, otherwise, the data will be overwritten.
|
||||
static void set_module_raw(const std::array<uint8_t, 4>& segments);
|
||||
|
||||
/// Sets the module timer digit to the given raw segments.
|
||||
///
|
||||
/// You should ensure the module timer is disabled before
|
||||
/// calling this, otherwise, the data will be overwritten.
|
||||
///
|
||||
/// `digit` should be in the range 0..=3.
|
||||
static void set_module_digit_raw(uint8_t digit, uint8_t segments);
|
||||
|
||||
/// Sets the rollover logic for the game timer.
|
||||
///
|
||||
/// If `true`, when the timer reaches zero, it will go
|
||||
/// negative, and start counting up.
|
||||
/// If `false`, when the timer reaches zero, it will stop
|
||||
/// the timer.
|
||||
static void game_timer_rollover(bool rollover);
|
||||
|
||||
/// Sets the rollover logic for the module timer.
|
||||
///
|
||||
/// If `true`, when the timer reaches zero, it will go
|
||||
/// negative, and start counting up.
|
||||
/// If `false`, when the timer reaches zero, it will stop
|
||||
/// the timer.
|
||||
static void module_timer_rollover(bool rollover);
|
||||
|
||||
/// Gets the current game time in millis.
|
||||
static int32_t get_game_time();
|
||||
|
||||
/// Gets the current module time in millis.
|
||||
static int32_t get_module_time();
|
||||
|
||||
/// Waits until all commands are flushed to the seven segments.
|
||||
static void flush();
|
||||
|
||||
/// Waits until the game timer is zero (or negative).
|
||||
static void wait_game_timer_done();
|
||||
|
||||
/// Waits until the module timer is zero (or negative).
|
||||
static void wait_module_timer_done();
|
||||
|
||||
/// Sets the intensity of the display.
|
||||
///
|
||||
/// `intensity` gets clamped to the range `0..=7`
|
||||
static void set_intensity(uint8_t intensity);
|
||||
|
||||
};
|
||||
|
||||
void init_ssegs();
|
||||
|
||||
#endif // SSEGS_HPP
|
||||
Reference in New Issue
Block a user