Robot Control Library
rc_blink.c
/**
* @file rc_blink.c
* @example rc_blink
*
* This is an example program to demonstrate use of LEDs and button handlers in
* the Robot Control API. Once started, blink will flash the green and red LEDs.
* Pressing the mode button will cycle through 3 blinking speeds, slow medium,
* and fast. Momentarily pressing the pause button will stop and start the
* blinking by toggling the global state between PAUSED and RUNNING. If the user
* holds the pause button for more than 1.5 seconds then the blink program will
* flash the red LED and exit cleanly.
*
* This should be used as a reference for how to handle buttons and how to
* control program flow cleanly utilizing rc_get_state() and rc_set_state().
**/
#include <stdio.h>
#include <rc/button.h>
#include <rc/led.h>
#include <rc/start_stop.h>
#include <rc/time.h>
#define QUIT_TIMEOUT_US 1500000 // quit after 1.5 seconds holding pause button
#define QUIT_CHECK_US 100000 // check every 1/10 second
// mode=0,1,2 corresponds to us_delay index for slow,medium,fast
static const int us_delay[] = {400000, 170000, 100000};
static int mode;
static int toggle; // toggles between 0&1 for led blink
/**
* Make the Pause button toggle between paused and running states.
*/
static void __on_pause_release(void)
{
// toggle betewen paused and running modes
printf("PAUSED\n");
}
else if(rc_get_state()==PAUSED){
printf("RUNNING\n");
}
fflush(stdout);
return;
}
/**
* If the user holds the pause button for 2 seconds, set state to exiting which
* triggers the rest of the program to exit cleanly.
*/
static void __on_pause_press(void)
{
int i=0;
const int samples = QUIT_TIMEOUT_US/QUIT_CHECK_US;
// now keep checking to see if the button is still held down
for(i=0;i<samples;i++){
rc_usleep(QUIT_CHECK_US);
return;
}
}
printf("long press detected, shutting down\n");
return;
}
/**
* If the user holds the pause button for 2 seconds, set state to exiting which
* triggers the rest of the program to exit cleanly.
*/
static void __on_mode_release(void)
{
if(mode<2) mode++;
else mode=0;
printf("setting mode: %d\n", mode);
return;
}
/**
* main function sits in one while loop blinking LEDs while button handlers
* control the blink speed and program state
*/
int main()
{
// make sure another instance isn't running
// if return value is -3 then a background process is running with
// higher privaledges and we couldn't kill it, in which case we should
// not continue or there may be hardware conflicts. If it returned -4
// then there was an invalid argument that needs to be fixed.
if(rc_kill_existing_process(2.0)<-2) return -1;
// start signal handler so we can exit cleanly
fprintf(stderr,"ERROR: failed to complete rc_enable_signal_handler\n");
return -1;
}
// initialize pause and mode buttons
fprintf(stderr,"ERROR: failed to init buttons\n");
return -1;
}
fprintf(stderr,"ERROR: failed to init buttons\n");
return -1;
}
// Assign functions to be called when button events occur
rc_button_set_callbacks(RC_BTN_PIN_PAUSE, __on_pause_press, __on_pause_release);
rc_button_set_callbacks(RC_BTN_PIN_MODE, NULL, __on_mode_release);
// start with both LEDs off
if(rc_led_set(RC_LED_GREEN, 0)==-1){
fprintf(stderr, "ERROR in rc_blink, failed to set RC_LED_GREEN\n");
return -1;
}
if(rc_led_set(RC_LED_RED, 0)==-1){
fprintf(stderr, "ERROR in rc_blink, failed to set RC_LED_RED\n");
return -1;
}
// make PID file to indicate your project is running
// due to the check made on the call to rc_kill_existing_process() above
// we can be fairly confident there is no PID file already and we can
// make our own safely.
// prepare to run
mode = 0;
printf("\nPress mode to change blink rate\n");
printf("hold pause button to exit\n");
// Run the main loop untill state is EXITING which is set by hitting ctrl-c
// or holding down the pause button for more than the quit timeout period
while(rc_get_state()!=EXITING){
// if the state is RUNNING (instead of PAUSED) then blink!
if(toggle){
toggle = 0;
}
else{
toggle=1;
}
}
// sleep the right delay based on current mode.
rc_usleep(us_delay[mode]);
}
// now that the while loop has exited, clean up neatly and exit compeltely.
return 0;
}
#define RC_BTN_PIN_PAUSE
Definition: button.h:26
int rc_button_get_state(int chip, int pin)
used to query the position of a button.
int rc_button_init(int chip, int pin, char polarity, int debounce_us)
Initializes a single button handler.
int rc_button_set_callbacks(int chip, int pin, void(*press_func)(void), void(*release_func)(void))
Sets the callback functions to be called when the button is pressed or released.
#define RC_BTN_PIN_MODE
Definition: button.h:27
void rc_button_cleanup(void)
Closes all button handlers. Call at the end of your program before returning.
#define RC_BTN_DEBOUNCE_DEFAULT_US
Definition: button.h:35
#define RC_BTN_STATE_RELEASED
Definition: button.h:30
#define RC_BTN_POLARITY_NORM_HIGH
Definition: button.h:32
int rc_led_set(rc_led_t led, int value)
sets the state of an LED
void rc_led_cleanup(void)
closes file descriptors to all opened LEDs
@ RC_LED_GREEN
Definition: led.h:36
@ RC_LED_RED
Definition: led.h:37
rc_state_t rc_get_state(void)
fetches the current process state as set by the user or signal handler
int rc_remove_pid_file(void)
Removes the PID file created by rc_make_pid_file().
void rc_set_state(rc_state_t new_state)
sets the current process state.
int rc_make_pid_file(void)
Makes a PID file RC_PID_FILE (/run/shm/robotcontrol.pid) containing the current PID of your process.
int rc_enable_signal_handler(void)
Enables a generic signal handler. Optional but recommended.
int rc_kill_existing_process(float timeout_s)
This function is used to make sure any existing program using the PID file is stopped.
@ RUNNING
Definition: start_stop.h:62
@ EXITING
Definition: start_stop.h:64
@ PAUSED
Definition: start_stop.h:63
void rc_usleep(unsigned int us)
Sleep in microseconds.