283 lines
8.9 KiB
C++
283 lines
8.9 KiB
C++
#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
|