Page MenuHomec4science

buttons.c
No OneTemporary

File Metadata

Created
Sun, Sep 1, 17:52

buttons.c

/*
buttons.c
Copyright (C) 2011 Michiel D'Haene <michiel.dhaene at gmail dot com>
UGent Reservoir lab (http://reslab.elis.ugent.be/michiel)
Ghent University (http://www.ugent.be)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
\defgroup buttons BUTTONS
\brief onboard buttons handling.
This module is responsible for reading the state of the buttons and executing button commands if required
\author Michiel D'Haene
\version 2.0
\date 2011-08-12
*/
/*@{*/
/** \file buttons.c
\brief onbaord buttons handling.
*/
#include "buttons.h"
#include <xc.h>
#include <sbcp.h>
#include <packet.h>
#include <sbcp_common.h>
#include "timer.h"
#include "pindefs.h"
#include "speaker.h"
#include "spi_led.h"
#include "power_sbcp.h"
#include "adc.h"
/*************************************************************************
*
* VARIABLES
*
*************************************************************************/
epower_state power_state;
ebutton_state SW2_state, SW3_state;
extern unsigned int systime;
unsigned int SW1_count;
unsigned int SW2_count;
unsigned int SW3_count;
unsigned int shutdown_time;
/*************************************************************************
*
* FUNCTIONS
*
*************************************************************************/
/** \brief Init buttons
Initialize parameters of the buttons.c file.
\param no parameters
\return no return value
*/
void init_buttons(void) {
// if the PIC is powered, power is always on
power_state = POWER_ON_WAITING_FOR_BUTTON_RELEASE;
SW2_state = BUTTON_NOT_PRESSED;
SW3_state = BUTTON_NOT_PRESSED;
// own power supply is on
POWER_EN = 1;
set_power_supplies();
}
/** \brief Set power supplies according to monitor state
Set power supplies according to monitor state
\param no parameters
\return no return value
*/
void set_power_supplies(void) {
if(sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) & ENABLE_SERVO){
SERVO_VOLTAGE_EN = 1;
}else{
SERVO_VOLTAGE_EN = 0;
}
if(sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) & ENABLE_MOTOR){
MOTOR_VOLTAGE_EN = 1;
}else{
MOTOR_VOLTAGE_EN = 0;
}
if(sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) & ENABLE_LOGIC){
DIGITAL_VOLTAGE_EN = 1;
}//can't disable logic directly!
}
/** \brief Function executed over SBCP
Function executed over SBCP
\param no parameters
\return no return value
*/
void host_is_up(unsigned int * buffer){
if (power_state != SWITCH_POWER_OFF
&& power_state != WAIT_FOR_MASTER_READY_TO_POWER_OFF
&& power_state != WAIT_FOR_MASTER_READY_TO_SHUTDOWN) {
power_state = POWER_ON;
sbcp_prepare_r_packet(0,SBCP_NO_ERROR);
sbcp_mark_r_packet_ready();
}else{
sbcp_send_error_r_packet(SBCP_CERR_UNKNOWN_INSTRUCTION);
}
}
/** \brief Check power button state
This function is used to check the current state of the power button.
It also controls the power on and power off routines.
When power button is pressed, it initiates the power-off routine and
switched off power completely when allowed by the main program.
This is a finite state machine implementation
\param no parameters
\return 1 if device is switching off, 0 otherwise
*/
uint8 check_powerbutton(void) {
// debounced power button state
int power_button_pressed;
// check if power button is released
if (SW1 != 0) {
// reset hold-down counter
SW1_count = systime;
}
// if power button is hold for FORCE_POWER_OFF_HOLD_TIME, force the device to power off
if (systime - SW1_count > FORCE_POWER_OFF_HOLD_TIME) {
power_state = SWITCH_POWER_OFF;
}
// if power button is hold for POWER_BUTTON_DEBOUNCE time, a valid key press is read
if (systime - SW1_count > BUTTON_DEBOUNCE) {
power_button_pressed = TRUE;
} else {
power_button_pressed = FALSE;
}
// only set power supplies from master flags when power state allows this
if (power_state != SWITCH_POWER_OFF && power_state != WAIT_FOR_MASTER_READY_TO_POWER_OFF) {
set_power_supplies();
}
switch (power_state) {
case POWER_ON_WAITING_FOR_BUTTON_RELEASE:
set_RGB_led(LD4, 0, 0, 1);
// if powerbutton is released, go to the next state
if (SW1 == 1) {
power_state = POWER_ON_WAITING_FOR_HOST_UP;
SW1_count = systime;
}
break;
case POWER_ON_WAITING_FOR_HOST_UP:
set_RGB_led(LD4, 0, 0, 1);
if (power_button_pressed == TRUE){
power_state = WAIT_FOR_MASTER_READY_TO_SHUTDOWN;
shutdown_time = systime;
}
break;
case POWER_ON:
set_RGB_led(LD4, 0, 1, 0);
// check for power down requests
if ((power_button_pressed == TRUE)
|| ! (sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) & ENABLE_LOGIC)
|| (sbcp_reg_uint(ADDRESS_POWER_STATUS) & POWERBOARD_VOLTAGE_UNDER_MIN)) {
sbcp_reg_uint(ADDRESS_POWER_STATUS) |= POWERBOARD_SHUTDOWN_BUTTON_REQUEST;
power_state = WAIT_FOR_MASTER_READY_TO_SHUTDOWN;
shutdown_time = systime;
}
break;
case WAIT_FOR_MASTER_READY_TO_SHUTDOWN:
set_RGB_led(LD4, 1, 1, 0);
// blink power-led
set_led(POWER_LED, BLINK);
// wait until bus master allows to power off supplies
if (!(sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) & ENABLE_LOGIC)
|| ((systime - shutdown_time) > WAIT_BEFORE_INITIATING_SHUTDOWN_ANYWAY)
|| (sbcp_reg_uint(ADDRESS_POWER_STATUS) & POWERBOARD_VOLTAGE_UNDER_MIN)
) {
power_state = WAIT_FOR_MASTER_READY_TO_POWER_OFF;
shutdown_time = systime;
}
break;
case WAIT_FOR_MASTER_READY_TO_POWER_OFF:
set_RGB_led(LD4, 1, 1, 0);
set_led(POWER_LED, BLINK_FAST);
// switch off power converters
sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) &= ~ENABLE_SERVO;
sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) &= ~ENABLE_MOTOR;
set_power_supplies();
set_RGB_led(LD3, 1, 0, 0);
set_RGB_led(LD2, 1, 0, 0);
if ((systime - shutdown_time) > WAIT_AFTER_SBCP_SHUTDOWN_COMMAND){
power_state = SWITCH_POWER_OFF;
}
break;
case SWITCH_POWER_OFF:
sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) &= ~ENABLE_SERVO;
sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) &= ~ENABLE_MOTOR;
set_power_supplies();
set_RGB_led(LD3, 1, 0, 0);
set_RGB_led(LD2, 1, 0, 0);
// short sound feedback
DIGITAL_VOLTAGE_EN = 0;
set_RGB_led(LD4, 1, 0, 0);
beep_goodbye();
POWER_EN = 0; // switch off own power supply
set_RGB_led(LD1, 1, 0, 0);
// no other stuff to do anymore, wait until charge is drowned
while (1);
beep_error();//this shouldn't happen, the code should never arrive here
break;
default:
power_state = POWER_ON_WAITING_FOR_BUTTON_RELEASE;
}
return power_button_pressed;
}
/** \brief Emergeny shutdown
Shutdown the board due to an emergency
\param the color of the leds during the shutdown
\return 1 if switch SW2 is pressed, 0 otherwise
*/
void emergency_shutdown(int red, int green, int blue){
MOTOR_VOLTAGE_EN = 0; //first motors
SERVO_VOLTAGE_EN = 0; //then servos
DIGITAL_VOLTAGE_EN = 0; //then RB-110
set_speaker_volume(VOLUME_4);
set_speaker_freq(NOTE_E6);
set_RGB_led(LD4, red, green, blue);
set_RGB_led(LD3, red, green, blue);
set_RGB_led(LD2, red, green, blue);
set_RGB_led(LD1, red, green, blue);
POWER_EN = 0; // switch off own power supply
// no other stuff to do anymore
while (1);
}
/** \brief Check power button state
This function checks the state of button SW2.
\param no parameters
\return 1 if switch SW2 is pressed, 0 otherwise
*/
uint8 check_SW2(void) {
// check if power button is released
switch (SW2_state) {
case BUTTON_NOT_PRESSED:
if (SW2 != 0) {
// reset hold-down counter
SW2_count = systime;
}
if (systime - SW2_count> BUTTON_DEBOUNCE) {
// put here commands to be executed when the button is pressed
sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) ^= ENABLE_SERVO; //toggle servo supply
SW2_state = BUTTON_PRESSED;
return 1;
}
break;
case BUTTON_PRESSED:
if (SW2 != 1) {
// reset hold-down counter
SW2_count = systime;
}
if (systime - SW2_count> BUTTON_DEBOUNCE) {
// put here commands to be executed when the button is released
SW2_state = BUTTON_NOT_PRESSED;
return 0;
} else {
// put here commands to be executed when the button is hold
return 1;
}
break;
default:
SW2_state = BUTTON_NOT_PRESSED;
}
return 0;
}
/** \brief Check power button state
This function checks the state of button SW3.
\param no parameters
\return 1 if switch SW3 is pressed, 0 otherwise
*/
uint8 check_SW3(void) {
switch (SW3_state) {
case BUTTON_NOT_PRESSED:
if (SW3 != 0) {
// reset hold-down counter
SW3_count = systime;
}
if (systime - SW3_count> BUTTON_DEBOUNCE) {
sbcp_reg_uint(ADDRESS_POWER_MONITOR_MODE) ^= ENABLE_MOTOR; //toggle motorboard supply
SW3_state = BUTTON_PRESSED;
return 1;
}
break;
case BUTTON_PRESSED:
if (SW3 != 1) {
// reset hold-down counter
SW3_count = systime;
}
if (systime - SW3_count> BUTTON_DEBOUNCE) {
// put here commands to be executed when the button is released
SW3_state = BUTTON_NOT_PRESSED;
return 0;
} else {
// put here commands to be executed when the button is hold
return 1;
}
break;
default:
SW3_state = BUTTON_NOT_PRESSED;
}
return 0;
}
/** \brief Check buttons
Check whether a button on the powerboard is pressed and act upon it.
\param no parameters
\return 1 if device is switching off, 2 if SW2 is pressed,
4 if SW3 is pressed, or combination of more than one button
*/
uint8 check_buttons(void) {
uint8 return_value;
return_value = check_powerbutton();
check_SW2();
check_SW3();
if (SW2 == 0) return_value += 2;
if (SW3 == 0) return_value += 4;
return return_value;
}
/*@}*/

Event Timeline