08
Scoreboards seem to be quite popular as beginner projects but the results are often very specific to the hardware used and very ‘hard coded’ to the original purpose.
It seemed to me that there are some parts of this style of application that are generic and probably independent to the type of scoreboard (sport and/or hardware used). I wanted to explore which parts and how this could drive a generic framework to create and update any scoreboard.
Scoreboard basics
A scoreboard is a large board, for example at a sports ground or stadium, on which the score in a game or match is displayed for the audience and participants. This display is typically square or rectangular in shape and contains all of the information relevant the sport/game such as home and guest score, game elapsed time, quarter/half indicator, other clock information, etc.
A good scoreboard is simple – it should be easy to read and quick to understand. It should contain clear information specific to the game being played and may include important game metrics. These metrics can greatly complicate the layout and size of displays for some sports – in my experience Cricket is an extreme example (shown below).
So what’s generic about this?
For simplicity I’ll just consider a sports scoreboard similar to the type shown below.
Analyzing the data displayed by this style of scoreboard, we can see a limited range of types of information:
- Numeric Fields. By far the majority of information on a scoreboard consists of numeric fields.
- Clocks. There is usually at least one game clock (duration or countdown) and often a second clock (eg, a shot clock in basketball).
- Static Elements. These are labels (Home, Guest, Score, etc) and separation lines that don’t change during the course of the game. These invariant elements are often built into the physical construction of the scoreboard.
Some labels may be static just for one match (player names, team names) and these are often handled using replaceable signs or as text fields on software driven displays. - Graphical Elements. Some data elements may be represented in graphical form such as dots, lines or icons. The underlying data is usually numeric (for example true/false or a count).
Building a framework
The framework described here is included in the scoreboard examples (the file scoreboard.h in MD_MAXPanel_SB_*) accompanying the MD_MAXPanel library. While the current framework uses a 40×32 LED panel as the scoreboard, it should be straightforward to change for alternative output hardware.
Defining the Scoreboard
For me, a useful framework takes the display and clock management functions away from the application and allows it concentrate on the functionality required for the scoreboard operator.
So, as a starting point, this means that all display field management will happen within the framework code (a C++ class in this implementation). Fields in this class are represented as a linked list of field attributes created by the application when defining the scoreboard. Each entry in the list is given a unique application defined numeric identifier id by the application.
enum fieldType_t
{
NUMBER, ///< a simple number
MMMSS, ///< time MMM:SS displayed
MMSS, ///< time MM:SS displayed
SS ///< time SS display only
};
struct field_t
{
uint8_t id; ///< identifier
fieldType_t type; ///< field type
uint8_t x, y; ///< field coordinates
uint32_t value; ///< current value of the field
bool leadZero; ///< field has leading zeroes
uint8_t size; ///< field size in characters/numbers
field_t* next; ///< next in the list
};
The field has a coordinate x, y for its top left corner, a size (displayed characters), including the colon for time and leading zeroes if specified. The type of field determines how to interpret and display its current value. For clocks the current time is uniformly stored in seconds but can be displayed in the different formats specified.
A clock is a field that has associated with it additional information. A game clock will have a timeLimit it counts up to (or down from), a boolean status of whether it is stopped, and some in ternal management.
struct clock_t
{
field_t* f; ///< field associated with this timer
uint32_t timeLimit; ///< upper limit for time
uint32_t timeLast; ///< last time displayed/updated
uint32_t timeToGo; ///< time to go before next update
bool countUp; ///< counting up if true
bool stopped; ///< true if stopped
};
To define a scoreboard an application needs to define the displayed fields (using fieldCreate()) and then associate a clock with those fields that are clocks (clockCreate()).
Managing Field Values
Fields only contain numeric values, so simple class methods to manage each field are fieldSetValue(), fieldGetValue() and fieldValueAdd() which do the obvious suggested by the method name.
Managing Clocks
For the clock fields the value is managed by the class rather than the application, although the field*() methods will still work correctly.
The clock value is incremented or decremented each second by the class. The application manipulates the status of a clock using
- clockStart() to stat the clock running.
- clockStop() to stop the clock running.
- clockToggle() to runs the clock if stopped and stops it if running.
- clockReset() to set the clock to the appropriate value depending on whether it is counting up or down.
- isClockRunning() to check its run status.
Display Updates
The application repeatedly calls the update() method to allow the class to run its management functions and update the display as required.
Updates are optimized to only change the display hardware when there has been a change to the scoreboard data. All changes occurring between after a call to update() are output at the next call to update().
Sample Applications
Simple scoreboard
The first application is a simple scoreboard showing 2 scores and a clock in MMSS format that counts up from zero time (example code MD_MAXPanel_SB_Simple).
The layout was planned using a spreadsheet to locate the fields and static elements of the display.
The prototype operator interface consists of a few tact switches managed by the MD_UISwitch library as follows:
- Clock Control – one switch to start and stop the clock. A long press resets the clock to zero.
- Score Up – one switch per score field to add +1 to the score.
- Score Down – One switch per score field to add -1 to the score. A long press resets the associated score to zero.
The final scoreboard is shown below. The static elements (lines) are drawn by the application during initialization.
Basketball scoreboard
To test the framework concepts further a more complex basketball scoreboard was created with 2 different clocks, more fields, more static elements and some graphical output (example code MD_MAXPanel_SB_BBall).
The display was planned on a spreadsheet, as before.
The operator interface consists of a few tact switches managed by the MD_UISwitch library as follows:
- Clock Control – one switch to start and stop the clock. A long press resets the clock to zero.
- Period Count Up – Increment the period counter. Once it reaches 4 it resets back to 0. The period is shown graphically as a sequence of 4 rectangles under the shot clock.
- Timeout Count Up – One switch per team to add +1 to the timeouts. Timeouts are reset to 0 once they reach 2. Timeouts are shown graphically as a line of 3 dots above the score.
- Score Up – One switch per score field to add +1 to the score.
- Score Down – One switch per score field to add -1 to the score. A long press resets the associated score to zero.
- Team Foul Up – One switch to increment the team foul count. Once this reaches 9 it resets to 0.
- Shot Clock Reset – One switch top reset the shot clock.
- Shot Clock Start/Stop – One switch to start and stop the shot clock.
Graphical elements are managed by the application as I could not find a ‘nice’ way to do this in the management class without creating excessive complexity in the class and how it is used.
The final scoreboard is shown below.
Conclusion
The results from this experiment are a bit of a mixed bag for me.
In simple applications, just showing scores and clocks, the framework works well and is a useful tool to simplify the management of the scoreboard.
However, if scoreboard graphical elements are included, I feel that the application still needs to do too much work outside of the management class, bringing it back into the ‘hard coded’ territory I was trying to avoid at the outset.
I may need to revisit this in future…