blk_box_lib/include/blk_box_drivers/ssegs.hpp
2026-04-04 16:35:45 -05:00

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