Scoreboards and Video Routing in Python

Controlling a Video Matrix

Although the basic operation of a matrix router is fairly simple to understand, it's always easier to have meaningful names and labels attached instead of remembering sets of numbers. Adding some shortcuts to common configurations makes things even easier, which is the purpose of the matrix control program (not shown, but available online [3]).

The Raspberry Pi communicates with the matrix over a USB serial connection set up in Python:

class matrixSerial:
  def __init__ ( self ):
    self.port = serial.Serial ( "/dev/ttyUSB0" , 9600 )
  def send ( self , cmd ):
    self.port.write ( cmd )

The __init__ line creates self.port, which is an instance of the Serial object with the name of the serial device and the requested baud rate. The defaults are fine for everything else. The send function takes in cmd and transmits it with a call to self.port.write, thus sending data to the matrix.

The Button Class

The main function of the program is to present easy options to the user on a touchscreen; a button class sets up the actions to button presses. When the class is instantiated, it receives screen, which is a reference to the Pygame screen object, and font, which is a Pygame font object to be used to label the buttons. Each of these is stored in class properties for use by other methods.

When the create function is called, it receives a number of variables to get started, including the x and y screen coordinates where the button should be drawn, the width and height of the button, and the label text displayed on the button. self.rect stores the Pygame rect object, which has functions to check whether coordinates are within its bounds, along with several other useful utilities, and self.matrixCommands and self.osCommands are the actions taken when the button is pressed.

The addOsCommand function takes its associated string argument and passes it to the operating system when the button is pressed:

def addOsCommand ( self , cmd ):
  self.osCommands.append ( cmd )

The addMatrixCommand function is the same, except it transmits to the matrix.

The render function is responsible for drawing the button on the screen. As you have seen before, it creates a surface and fills it – with green in this case. If its label is not empty, the program renders the text, calculates how to center the text, and adds the text to the button blit. The surface is then drawn to the screen with a reference saved to its Pygame rect.

The Matrix Class

The matrix class draws and manages the interface on the touchscreen. As usual, an __init__ function initializes the different components of the interface, but this example has a lot of them. The graphics system starts and creates a window to draw on. Although the window has a caption, it is generally not visible because the window is in fullscreen mode.

As usual, the fonts and serial communications are initialized, although pygame.font.SysFont has an empty string as its first argument, thus asking Pygame for the default font:

buttonFont = pygame.font.SysFont ( "" , 32 )
self.matrixPort = matrixSerial()

The next line creates self.buttons as a list, which is where each of the buttons added to the interface are stored. Most of the rest of the init function creates each of the buttons and defines their functionality. They all follow the general format:

btn = button (self.screen, buttonFont)
btn.create ( <x> , <y> , <width> , <height , "<label" )
btn.addMatrixCommand ( chr ( 0x05 ) + chr ( 0x55 ) +chr ( 0x19 ) + chr ( 0x00 ) )
btn.addMatrixCommand ( chr ( 0x05 ) + chr ( 0x55 ) +chr ( 0x19 ) + chr ( 0x11 ) )
self.buttons.append ( btn )

The first line creates a button and passes in self.screen and buttonFont. The create makes the button, and addMatrixCommand adds commands for the video matrix. The command string comes from the matrix documentation; it tells you to send the first three hex values to start the command. The last byte contains the routing as 0 indexed addresses. The high-order digit defines the output or destination, and the low-order digit defines the input or source. Here, 0x00 says "connect the first output to the first input." The next line connects the second output to the second input. Table 1 shows the configuration for each button.

Table 1

Buttons and Configurations

Line Nos.

Button

Action

57-61

Separate Scoreboards

Each display shows its own scoreboard computer.

63-67

Single Scoreboard

Both screens display the first scoreboard computer.

69-73

Both Program

Both screens display the video switcher program output.

75-78

Court A Program

Switch only the court A screen to the video switcher output.

80-83

Court B Program

Switch only the court B screen to the video switcher output.

85-88

Court A Scoreboard A

Switch only the court A screen to its scoreboard computer.

90-93

Court B Scoreboard B

Switch only the court B screen to its scoreboard computer.

95-98

CR Gym 1 Action

View Scoreboard (NUC) 1 on the control room monitor.

100-103

CR Gym 2 Action

View Scoreboard (NUC) 2 on the control room monitor.

105-108

CR Program Action

View the video switcher program output on the control room monitor.

110-113

Record

Start recording onto an SD card or flash drive.

115-118

Stop

Stop recording.

One output of the matrix is connected to a monitor in the control room so that the sources can be easily monitored. The three CR buttons allow any of the matrix sources to be viewed on the control room monitor (Figure 7).

Figure 7: The switcher multiview shows all of the cameras and other sources available. They can be put "on air" by clicking on them.

All of the buttons except the last two use addMatrixCommand. The Record and Stop buttons use addOsCommand instead and then use wget to trick the digital recorder into thinking the buttons on its web GUI are being pressed to start and stop the recording onto an SD card or flash drive (Listing 2).

Listing 2

wget Trick

btn.addOsCommand ( r'wget --header="Accept:*/*" --header="Accept-Encoding: gzip, deflate" --header="Accept-Language: en-US,en;q=0.9" --header="Connection: keep-alive" --header="Cookie: serenity-session=72952074" --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "http://172.16.2.20/cgi-bin/system.cgi?command=recording&action=start"' )

The render function iterates over self.buttons, calling each render method and creating all of the buttons onscreen, as well as all the Pygame rect objects to see whether they've been clicked. Once everything has been drawn to the buffer, the function calls pygame.display.flip to make it visible in the drawing window.

The loop function makes everything interactive by watching for buttons presses, sending commands when they are, and keeping up with everything that's happening.

The looping value is first set to True, before the function enters the while loop with looping as its argument. If looping is set at any point to False, the loop exits.

The function then waits for Pygame events and checks to see if the event is a button click. To see if any of the buttons have been pressed, the function loops over self.buttons again and gets the coordinates of the mouse click:

for btn in self.buttons:
  if btn.rect.collidepoint ( event.pos ) == True:
     for cmd in btn.matrixCommands:
       self.matrixPort.send ( cmd + chr ( 0x77 ) )

If True, a button has been pressed. To make the button do its thing, the program loops over btn.matrixCommands and sends each string to the matrix. To give the matrix time to process each command, the function waits half a second before moving on.

The lines that follow do the same thing for any operating system commands (btn.osCommands) but pass them to os.system instead. The call to matrix on the last line of the program sets everything in motion.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Nerf Target Game

    A cool Nerf gun game for a neighborhood party provides a lesson in Python coding with multiple processors.

  • Gesture-Controlled Book

    Have you found yourself following instructions on a device for repairing equipment or been half-way through a recipe, up to your elbows in grime or ingredients, then needed to turn or scroll down a page? Wouldn't you rather your Raspberry Pi do the honors?

  • ReportLab and Panda3D

    A game of bingo illustrates how to use the ReportLab toolkit and Panda3D real-time 3D engine.

  • Panda3D

    Several free game engines are available for Linux users, but programming with them is often less than intuitive. Panda3D is an easy-to-use engine that is accessible enough for newcomers but still powerful enough for the pros at Disney Studios.

  • Perl: Skydiving Simulation

    Computer game programmers apply physical formulas and special tricks to create realistic animations. Simple DirectMedia Layer (SDL), which is available as a Perl wrapper, provides a powerful framework for creating simple 2D worlds with just a couple of lines of code.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News