Skip to content

Defining Buttons

jmalins edited this page Dec 27, 2012 · 6 revisions

Buttons are the main control sequencing element in VexOS. A Button instance in your robot program correspond to a joystick button, but they can also be made from digital inputs or more general software triggers. Buttons will start or stop Commands when they are pressed, released, held or toggled.

VexOS comes with a number of built-in Button classes, which may be all that is needed for most programs. See Built-in Buttons. However, there are certain sophisticated circumstances that required defining custom Buttons.

Like Commands, Buttons are discrete instances of a common Button class. For example, the Button class JoystickButton can have an instance for each button on a VEXnet controller. Defining a Button is conceptually similar to defining a Command class. Please read Defining Commands first, since only the unique information will be presented on this page.

Declaring a Button Class

Like Commands, custom Button classes must be declared in Robot.h. The format is similar to Commands, since you would also declare any enumeration types and public methods in the same place.

DeclareButtonClass(CustomButton);
CustomButton_setAwesomeLevel(Button*, int value);

The DeclareButtonClass(CustomButton) pre-processor macro declares the CustomButton variable, which is an extern reference to a variable of type ButtonClass. As an example, a public method is also declared for this Button, but this is not always required. For more on public methods, see Declaring Command and Button Public Methods.

Defining a Button Class

Once the Button class has been declared in Robot.h, you must create the actual implementation. By convention, each Button class should be defined in its own file. If using easyC, the file should be titled btn__NAME_.c, where NAME is the name of the ButtonClass, in [CamelCase][]. If not using easyC, then the suggested practice is to make a buttons/ directory in your robot project and place NAME.c files (without a prefix) in that directory.

A sample Button class declaration is as follows:

//
//  CustomButton.c
//
#include "ButtonClass.h"
#include "Robot.h"

/********************************************************************
 * Class Definition                                                 *
 ********************************************************************/

DefineButtonClass(CustomButton, {
    int awesomeThreshold;
    int awesomeLevel;
});

static void constructor(va_list argp) {
    self->fields->awesomeThreshold = va_arg(argp, int);
    self->fields->awesomeLevel     = 0;
}

static bool get() {
    return (self->fields->awesomeLevel >= self-fields->awesomeThreshold);
}

/********************************************************************
 * Public API                                                       *
 ********************************************************************/

void CustomButton_setAwesomeLevel(Button* button, int value) {
    checkInstance(button);
    button->fields->awesomeLevel = value;
}

A Button class will always include ButtonClass.h, as this header contains all of the magic needed to create the ButtonClass variable. ButtonClass.h should only be include in Button class definition C files and should not be included in any other type of file. This header is part of VexOS and should have been imported into your project previously, see Using VexOS in easyC.

You would also include Hardware.h if your Button deals with hardware. Note however, that hardware can only be constructed in the startup / constructor phase of VexOS. The best way around this restriction is to make your custom Button instances global variables and create them in the constructor of your Robot.

The next include is Robot.h, which contains the declaration of this Button class, as well as all Subsystems and Commands.

DefineButtonClass(name, { fields }) Statement

The next component is the DefineButtonClass(name, { fields }) pre-processor macro. This is what actually creates the variable of type ButtonClass and links it up to everything else defined in the C file. The first argument is the name of the Button class. This should exactly match the name given to DeclareButtonClass(name) in the header file.

The next argument is a list of instance field declarations. For an in-depth discussion of the field declarations, see Defining Commands.

Button Constructor

The button constructor is a function that is called when a Button instance is created by a call to Button_new(&class, ...). Unlike the constructors for Subsystems and the Robot, which are called as part of system start-up, the Button constructor is not called until the Button class is instantiated.

The argument of type va_list are the arguments passed to Button_new(&class, ...). This implementation for Buttons is exact the same as for Commands, see Defining Commands.

Get Method

A button class has only one internal method that must be implemented, that is the get() method. This method returns a boolean value indicating whether the Button is considered "pressed" or not. In our example CustomButton, the button is pressed if the awesomeness level is greater than a pre-determined threshold.

You should avoid creating get() implementations that have side effects (i.e. write changes somewhere when called). This is because you cannot know in advance how many times get() will be called by the VexOS infrastructure. The exact number depends on what types of Command bindings are present. If a custom Button class must do something exactly once per robot cycle, you need to register a periodic event handler (see VexOS Events), do your computation in that handler, then write the result to a Button field variable. The get() method can then read from the field as many times as needed.

Public Methods

Like Commands, Button classes can also have additional public methods. In the case of Buttons, public methods are significantly more useful than with Commands. For how to define public methods on Button classes, see Declaring Command and Button Public Methods.

Clone this wiki locally