#include #include #include "bughal.h" #include "util.h" //for timer /* Hardware abstraction layer for Pentabug hardware */ /* * initialize LEDs on C0-C3 */ static uint8_t oldinput; // button readings from last poll cycle static uint8_t curinput; // button readings from current poll cycle //each switch has its own state machine static uint8_t btnstates[BTN_BUTTONS]; //array for current button states static uint8_t btncounters[BTN_BUTTONS]; //individual counter for button state machine static timer_t btntimers[BTN_BUTTONS]; //individiual timer for for button state machine void init_leds(void) { //enable LED channels as output DDRC |= (1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3); // both LEDs off PORTC &= ~((1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3)); return; } inline void led_on(int leds) { PORTC |= leds; } inline void led_off(int leds) { PORTC &= ~leds; } void init_buzzr(void) { // its on B2 and C5 DDRC |= (1 << PORTC5); DDRB |= (1 << PORTB2); // switch it off buzzr_off(); return; } void init_mic(void) { // buzzer is on B2 and C5, for reasons // ... we use it as microphone DDRC &= ~(1 << PORTC5); // switch C5 to input DDRB |= (1 << PORTB2); // B2 as output PORTB &= ~(1 << PORTB2); //and to GND ADMUX = (1 << REFS1) | (1 << REFS0); // use internal 1.1V as reference ADCSRA = (1 << ADPS1) | (1 << ADPS0); // prescaler F_CPU/8 ADCSRA |= (1 << ADEN) | (1 << ADATE); // ADC enable - turn it on in free running mode ADCSRB &= (1 << ACME); //leave only ACME as it is (others zerp for free running) ADMUX = (ADMUX & ~(0x1F)) | 5; // select channel 5 ADCSRA |= (1 << ADSC); // start conversion uint16_t __attribute__((unused)) dummy = ADCW; //read once return; } void buzzr_up(void) { // one pin Vcc, other GND PORTC &= ~(1 << PORTC5); PORTB |= (1 << PORTB2); return; } ; void buzzr_down(void) { // one pin GND,other pin Vcc PORTC |= (1 << PORTC5); PORTB &= ~(1 << PORTB2); } inline void buzzr_off(void) { // both pins to GND PORTC &= ~(1 << PORTC5); PORTB &= ~(1 << PORTB2); } void buzzr_inv(void) { // read and invert pin settings, make the piezo flip polarity PORTC ^= (1 << PORTC5); PORTB ^= (1 << PORTB2); } void init_switch(void) { // init switch 1 and switch 2 DDRD &= ~((1 << PORTD1) | (1 << PORTD0)); // D0 and D1 as input PORTD |= (1 << PORTD1) | (1 << PORTD0); // pull-ups FTW // set predefined button states oldinput = 0; curinput = 0; // initialize the state machine of each button for (uint8_t i = 0; i < BTN_BUTTONS; i++) { btnstates[i] = BTNST_NTRL; //init button states btncounters[i] = 0; //init button counters timer_set(&btntimers[i], 0x05); //50ms - init button timers }; return; } bool switch_l(void) { return !(PIND & 0b00000001); } bool switch_r(void) { return !(PIND & 0b00000010); } void init_motor(void) { /* vibration motor on B1, initially off: */ DDRB |= (1 << PORTB1); PORTB &= ~(1 << PORTB1); return; } void set_motor(int val) { if (val == MOTOR_ON) { PORTB |= 0x02; } else { PORTB &= ~(0x02); } return; } // reset button to neutral state void button_clear(uint8_t button) { btnstates[button] = BTNST_NTRL; } void stateswitch(uint8_t i) { switch (btnstates[i]) { case BTNST_NTRL: if (curinput & (1 << i)) { //button down btncounters[i] = 0; btnstates[i] = BTNST_DBNC; } break; //intermediate state, check if button is still pressed to debounce case BTNST_DBNC: btnstates[i] = (curinput & (1 << i)) ? BTNST_SDN : BTNST_NTRL; (btncounters[i])++; break; case BTNST_SDN: if (curinput & (1 << i)) { btncounters[i]++; if (btncounters[i] > BTN_T_LONGFACT) { //500ms held btnstates[i] = BTNST_LDN; } } else { //button was released btnstates[i] = BTNST_SUP; //signal shortclick } break; case BTNST_LDN: if (!(curinput & (1 << i))) { //button was released btnstates[i] = BTNST_LUP; //signal longpress } break; case BTNST_SUP: if ((curinput & (1 << i))) { //button was pressed again or is bouncing after release btnstates[i] = BTNST_SUPDBNC; //going in special debounce btncounters[i] = 0; } break; case BTNST_LUP: if ((curinput & (1 << i))) { //button was pressed again or is bouncing after release btnstates[i] = BTNST_LUPDBNC; //going in special debounce btncounters[i] = 0; } break; case BTNST_SUPDBNC: if ((curinput & (1 << i))) { //button is still pressed --> going to shortpress btncounters[i]++; btnstates[i] = BTNST_SDN; //starting over from short pressed } else { btnstates[i] = BTNST_SUP; //nope, it was bouncing, back to old state } break; case BTNST_LUPDBNC: if ((curinput & (1 << i))) { //button is still pressed --> going to shortpress btncounters[i]++; btnstates[i] = BTNST_SDN; //starting over from short pressed } else { btnstates[i] = BTNST_LUP; //nope, it was bouncing, back to old state } break; default: //curently catches nothing // do nothing yet ; break; }; //end switch timer_set(&btntimers[i], BTN_T_DEBOUNCE); } void button_poll() { curinput = ~(PIND & 0b00000011); for (uint8_t i = 0; i < BTN_BUTTONS; i++) { if (timer_expired(&btntimers[i])) { stateswitch(i); } //end if timer expired } //end for oldinput = curinput; return; } bool btn_state(uint8_t btnstate, uint8_t btn) { return (btnstates[btn] == btnstate); }