Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Control Panel up/down button auto increment/decrement. #48

Closed
JonWoellhaf opened this issue Jan 29, 2020 · 0 comments
Closed

Control Panel up/down button auto increment/decrement. #48

JonWoellhaf opened this issue Jan 29, 2020 · 0 comments

Comments

@JonWoellhaf
Copy link

JonWoellhaf commented Jan 29, 2020

Here's a tiny improvement to the control panel up/down buttons. See the code below for a description of how the buttons will work.

If you want to try this,

  1. add the file ButtonStateMachine.cpp to the project.

  2. add these defines to ControlPanel.h
    #define NO_ACTION 0
    #define INCREMENT 1
    #define DECREMENT 2

  3. add this to UserInterface.h
    int ButtonStateMachine(bool incrementButtonPressed, bool decrementButtonPressed);

  4. in ControlPanel.cpp, change this line in getKeys to mask off the increment/decrement buttons so they are sent every loop.
    if( (newKeys.all) != (this->keys.all & 0xF8) )

  5. make these changes in UserInterface.cpp
    int action;
    ...
    if( keys.bit.FWD_REV )
    {
    this->reverse = ! this->reverse;
    // feed table hasn't changed, but we need to trigger an update
    newFeed = loadFeedTable();
    }

    action = ButtonStateMachine(keys.bit.UP, keys.bit.DOWN);

    if( action == INCREMENT )
    {
    newFeed = feedTable->next();
    }
    if( action == DECREMENT )
    {
    newFeed = feedTable->previous();
    }

// original code
// if( keys.bit.UP )
// {
// newFeed = feedTable->next();
// }
// if( keys.bit.DOWN )
// {
// newFeed = feedTable->previous();
// }


Here's the code for the button state machine:

// FILE: ButtonStateMachine.cpp
// DATE: 14 Jan 2020
// AUTHOR: Jan (Yan) Woellhaf
// jonwoellhaf@comcast.net
//
// Description:
// When I worked for Ampex in the 80's, I was introduced to a clever way
// to handle an up/down button pair.
//
// I'll describe how the Up button behaves. The Down button works the same,
// but values decrease, rather than increase.
//
// With both buttons not pressed, nothing changes.
//
// When Up is pressed the value immediately increments by one, and the
// initial delay timer starts.
//
// When the initial delay timer reaches its setting, say after one second,
// the value increments by one, and the auto slow delay timer starts.
//
// When the auto slow delay timer reaches its setting, say after a half
// second, the value increments and the auto slow delay timer is reset.
//
// This continues until the Up button is released.
//
// To this point, the action is quite normal. However, the interesting
// action happens when the Down button is pressed as the Up button
// continues to be pressed.
//
// With the direction established by the Up button, holding both
// buttons down accelerates the auto increment. Whereas increments
// were occurring twice per second, they now occur ten times per
// second.
//
// My contribution to this scheme was to create the state machine to
// control these actions. It's a good solution, because it forces the
// designer to consider every possible combination of button configurations
// and actions.
//
// I've seen many, many devices with Up/Down button pairs, but none have
// implemented this simple but effective scheme.

#include "F28x_Project.h"
#include "UserInterface.h"

// delays in units of control panel loops -- change as you prefer
#define INITIAL_DELAY 40 // delay before auto slow increment/decrement begins
#define SLOW_DELAY 18 // delay between changes in auto slow increment/decrement
#define FAST_DELAY 6 // delay between changes in auto fast increment/decrement

#define INPUT_NEITHER_BUTTON_PRESSED 0
#define INPUT_INCREMENT_BUTTON_PRESSED 1
#define INPUT_DECREMENT_BUTTON_PRESSED 2
#define INPUT_BOTH_BUTTONS_PRESSED 3

#define STATE_IDLE 0
#define STATE_WAIT_FOR_AUTO_SLOW_INCREMENT 1
#define STATE_WAIT_FOR_AUTO_SLOW_DECREMENT 2
#define STATE_AUTO_SLOW_INCREMENT 3
#define STATE_AUTO_SLOW_DECREMENT 4
#define STATE_AUTO_FAST_INCREMENT 5
#define STATE_AUTO_FAST_DECREMENT 6

int ButtonStateMachine(bool incrementButtonPressed, bool decrementButtonPressed)
{
static Uint16 loopCount = 0;
static Uint16 state = STATE_IDLE;
char buttonConfiguration;
int returnValue = NO_ACTION;

++loopCount;

    // get button configuration for input to state machine
if (decrementButtonPressed && incrementButtonPressed)
{
    buttonConfiguration = INPUT_BOTH_BUTTONS_PRESSED;
}
else if (decrementButtonPressed)
{
    buttonConfiguration = INPUT_DECREMENT_BUTTON_PRESSED;
}
else if (incrementButtonPressed)
{
    buttonConfiguration = INPUT_INCREMENT_BUTTON_PRESSED;
}
else
{
    buttonConfiguration = INPUT_NEITHER_BUTTON_PRESSED;
}

// set default returned action
returnValue = NO_ACTION;

switch (state)
{
    case STATE_IDLE:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_INCREMENT;
                returnValue = INCREMENT;
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_DECREMENT;
                returnValue = DECREMENT;
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                    // It would be difficult to press both buttons simultaneously
                    //   enough that one would not be read first.
                state = STATE_IDLE;
            break;
        }
    break;
    case STATE_WAIT_FOR_AUTO_SLOW_INCREMENT:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                if (loopCount >= INITIAL_DELAY)
                {
                    loopCount = 0;
                    state = STATE_AUTO_SLOW_INCREMENT;
                    returnValue = INCREMENT;
                }
                else
                {
                    state = STATE_WAIT_FOR_AUTO_SLOW_INCREMENT;
                }
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_DECREMENT;
                returnValue = DECREMENT;
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                loopCount = 0;
                state = STATE_AUTO_FAST_INCREMENT;
                returnValue = INCREMENT;
            break;
        }
    break;
    case STATE_WAIT_FOR_AUTO_SLOW_DECREMENT:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_INCREMENT;
                returnValue = INCREMENT;
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                if (loopCount >= INITIAL_DELAY)
                {
                    loopCount = 0;
                    state = STATE_AUTO_SLOW_DECREMENT;
                    returnValue = DECREMENT;
                }
                else
                {
                    state = STATE_WAIT_FOR_AUTO_SLOW_DECREMENT;
                }
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                loopCount = 0;
                state = STATE_AUTO_FAST_DECREMENT;
                returnValue = DECREMENT;
            break;
        }
    break;
    case STATE_AUTO_SLOW_INCREMENT:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                if (loopCount >= SLOW_DELAY)
                {
                    loopCount = 0;
                    returnValue = INCREMENT;
                }
                state = STATE_AUTO_SLOW_INCREMENT;
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_DECREMENT;
                returnValue = DECREMENT;
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                loopCount = 0;
                state = STATE_AUTO_FAST_INCREMENT;
                returnValue = INCREMENT;
            break;
        }
    break;
    case STATE_AUTO_SLOW_DECREMENT:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_INCREMENT;
                returnValue = INCREMENT;
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                if (loopCount >= SLOW_DELAY)
                {
                    loopCount = 0;
                    returnValue = DECREMENT;
                }
                state = STATE_AUTO_SLOW_DECREMENT;
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                loopCount = 0;
                state = STATE_AUTO_FAST_DECREMENT;
                returnValue = DECREMENT;
            break;
        }
    break;
    case STATE_AUTO_FAST_INCREMENT:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                // the decrement button has just been released
                // stop the auto fast increment and return to auto slow increment
                loopCount= 0;
                state = STATE_AUTO_SLOW_INCREMENT;
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                // the increment button has just been released
                // stop auto fast increment and go to auto slow decrement
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_DECREMENT;
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                // continue auto fast increment
                if (loopCount >= FAST_DELAY)
                {
                    loopCount = 0;
                    returnValue = INCREMENT;
                }
                state = STATE_AUTO_FAST_INCREMENT;
            break;
        }
    break;
    case STATE_AUTO_FAST_DECREMENT:
        switch (buttonConfiguration)
        {
            case INPUT_NEITHER_BUTTON_PRESSED:
                state = STATE_IDLE;
            break;
            case INPUT_INCREMENT_BUTTON_PRESSED:
                // the decrement button has just been released
                // stop auto fast decrement and return to auto slow increment
                loopCount = 0;
                state = STATE_WAIT_FOR_AUTO_SLOW_INCREMENT;
            break;
            case INPUT_DECREMENT_BUTTON_PRESSED:
                // the increment button has just been released
                // return to auto slow decrement
                loopCount = 0;
                state = STATE_AUTO_SLOW_DECREMENT;
            break;
            case INPUT_BOTH_BUTTONS_PRESSED:
                // continue auto fast decrement
                if (loopCount >= FAST_DELAY)
                {
                    loopCount = 0;
                    returnValue = DECREMENT;
                }
                state = STATE_AUTO_FAST_DECREMENT;
            break;
        }
    break;
    default:
        state = STATE_IDLE;
    break;
}
return returnValue;

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant