#ifndef SSEGS_HPP #define SSEGS_HPP #include #include #include #include /// 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, // SetGameRaw, SetModuleRaw std::pair, // 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 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 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& 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& 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