Join the Cedrus Community Forums


 

 

 

RB Series Support Home Page

 

Hardware Forum

 

 

 

 

Programming the RB Series Response Pads
Last Revision: July 25, 2002

The information in this article applies to:

  • Programmers who want to write their own software to communicate with the Cedrus RB-400, RB-410, RB-600, RB-610, RB-420, and RB-620 response pads

Summary

Cedrus' RB Series are directly supported by SuperLab. However, a number of users expressed an interest in using these popular response pads in their own applications. This document offers some technical information needed in order to write your own code.

Technical Details

The RB Series response pads send one and only one byte every time the state of one of the keys changes. See the document The RB Series Response Pads Protocol for information on the byte format.

Programming Notes

For the RB-400 or RB-600 response pads, open the serial port using 8-N-1 parameters at 2400 baud.

For the RB-410 or RB-610 response pads, open the serial port using 8-N-1 parameters at 9600 baud.

For the RB-420 or RB-620 response pads, open the serial port using 8-N-1 parameters at 9600, 19200, or 38400 baud, depending on the DIP switch settings.

Programming Example

Here is a sample source code on how to program the RB-4x0 and RB-6x0 response pads. This sample consists of the following four functions:

  • CedrusOpenSerialPort

  • CedrusCloseSerialPort

  • CedrusFlushSerialPort

  • CedrusGetButtonResponse. This function does not return until a key has been pressed.

Platforms

The sample code shown here is written for Windows 95 or later. The essential part is in the CedrusGetButtonResponse function. For other platforms, the main changes affect how the serial port is opened, read, and closed:

  • For Windows 3.1, you need to call the functions OpenComm, ReadComm, and CloseComm.

  • On the Macintosh, the needed functions are OpenDriver, SerSetBuf, SerGetBuf, FSRead, and CloseDriver.

Controlling the Serial Port

The following code is for controlling the serial port:

#include "windows.h"

// A few definitions to make the C code a
// little more readable


#define  EQ  ==
#define  NE   !=
#define  LT   <
#define  LE   <=
#define  GE   >=
#define  GT   >

#define  AND   &&               // Logical operators
#define  OR    ||
#define  NOT   !

#define  bAND   &               // Binary operators
#define  bOR    |
#define  bNOT   ~
#define  bXOR   ^

// Function prototypes

HANDLE CedrusOpenSerialPort (int nPortNum,
int nBaudRate);
int CedrusFlushSerialPort (HANDLE nPortHandle);
void CedrusCloseSerialPort (HANDLE nPortHandle);
int CedrusGetButtonResponse (HANDLE nPortHandle, int nRBModel);


HANDLE CedrusOpenSerialPort (
int nPortNum, int nBaudRate)
{
   
//  -- nPortNum should be set to 1 to open COM1,
    //     2 to open COM2, etc.
    //  -- nBaudRate should be a valid baud rate,
    //     e.g. 2400 or 9600
    //   
    //  This function returns -1 if it fails. If
    //  successful, it returns a "port handle" that
    //  is passed to other functions afterwards
    //  to access or close the serial port.

    char     port_name[8];
    HANDLE   port_handle;

    wsprintf (port_name, "COM%d", nPortNum);
    port_handle = CreateFile (port_name,
                        GENERIC_READ | GENERIC_WRITE,
                        0, NULL, OPEN_EXISTING, 0, NULL);

    if (port_handle EQ INVALID_HANDLE_VALUE)
    {
        port_handle = (HANDLE) -1;       // Return error
    }
    else
    {
        DCB             dcb;
        int             status;
        COMMTIMEOUTS   ct;

        status = GetCommState (port_handle, &dcb);

        // Setup serial port for 8-N-1
        // (8 bits, no parity, 1 stop bit)


        if (status NE 0)
        {
            dcb.BaudRate = nBaudRate;
            dcb.ByteSize = (unsigned char) 8;
            dcb.Parity = 0;
            dcb.StopBits = 0;
            dcb.fBinary = 1;             // No EOF check

            status = SetCommState (port_handle, &dcb);
        }

        // Setup timeouts

        ct.ReadIntervalTimeout = MAXDWORD;
        ct.ReadTotalTimeoutMultiplier = 0;
        ct.ReadTotalTimeoutConstant = 0;
        ct.WriteTotalTimeoutMultiplier = 0;
        ct.WriteTotalTimeoutConstant = 5000;
        SetCommTimeouts (port_handle, &ct);

        status = SetupComm (port_handle, 128, 128);

        CedrusFlushSerialPort (port_handle);
    }

    return port_handle;
}


int CedrusFlushSerialPort (HANDLE nPortHandle)
{
   
int      status = 0;
    short    done = FALSE;
    char      serial_buff[100];
    DWORD    bytes_read;

    while (NOT done)
    {
        status = ReadFile (nPortHandle, serial_buff,
                          
sizeof(serial_buff),
                           &bytes_read, NULL);

        if (status EQ 0)
            done = TRUE;                 // Error?!

        if (status NE 0 AND
            bytes_read LT sizeof(serial_buff))
        {
            done = TRUE;
        }
    }

    return status;
}


void
CedrusCloseSerialPort (HANDLE nPortHandle)
{
    CloseHandle (nPortHandle);
}

Checking the Status of the Buttons

The following code keeps looping until a pushbutton has been pressed on the response pad:

int CedrusGetButtonResponse (HANDLE nPortHandle, int nRBModel)
{
    //  nRBModel should be 1 for RB-400/RB-410, or
    //                      2 for RB-600/RB-610


    short    rb4x0[6] = {-1, -1, 0, 1, 2, 3 };
   
short    rb6x0[6] = {0, 5, 1, 2, 3, 4 };
   
int      num_bytes;
   
int      i, k;
   
int      button_pressed = FALSE;
   
short    buttons_status;
   
short    status;
    char      serial_buff[6];
    DWORD    comm_status;

    CedrusFlushSerialPort (nPortHandle);

    while (NOT button_pressed)
    {
        k = -1;
        serial_buff[0] = '\0';
        num_bytes = 0;
        buttons_status = 0;

        // See if a byte come from the serial port

        status = ReadFile (nPortHandle, serial_buff,
                           1, &comm_status, NULL);
        if (status NE 0)
            num_bytes = (short) comm_status;

        // Clear any overflow or other erros that might occur

        if (status EQ 0)
            ClearCommError (nPortHandle, &comm_status, NULL);

        // Convert to positive logic w/o the negative sign

       
if (num_bytes GT 0)
            buttons_status = (bNOT serial_buff[0]) bAND 0x003f;

       
if
(buttons_status GT 0)
        {
            i = 0;

            // This loop converts from an integer
            // to a bit number from 0 to 5


            while (i LT 6)
            {
                if ((1 << i) bAND buttons_status)
                {
                    k = i;
                    break;
                }

                i++;
            }

            // Re-map bit number to actual
            // button, depending on model


            if (nRBModel EQ 2)
                button_pressed = rb6x0[k] + 1;
            else
                button_pressed = rb4x0[k] + 1;
        }
    }

    return button_pressed;
}

 
That's it. The following sample code will simply call the functions shown above to illustrate how they are called and used:

void CedrusTestResponseBox (void)
{
    HANDLE   hPort;

    // Demo code for the RB-610
    // Open COM2 at 9600 baud (use 2400 for RB-400/RB-600)


    hPort = CedrusOpenSerialPort (2, 9600);

    if (hPort NE (HANDLE) -1)
    {
       
int     key_pressed;
        char     ch_buff[100];

        // Get response from RB-610. Change second
        //
parameter from 2 to 1 if using the RB-400
        // or RB-410.


        key_pressed = CedrusGetButtonResponse (hPort, 1);

        // Display a message to show the result

        wsprintf (ch_buff, "Button number %d was pressed!",
                  key_pressed);
        MessageBox (NULL, ch_buff, "Cedrus Code Snippet",
                    MB_OK | MB_ICONINFORMATION);

        CedrusCloseSerialPort (hPort);
    }
}

This code sample has been compiled and tested using Visual C++ 5.0.

 

 
© Copyright 2010 Cedrus Corporation, P.O. Box 6309, San Pedro, CA 90734 - USA
Toll Free: (800) 233-7871, other: (310) 548-9595. Send us an email or join mailing list