/* * userio.c: reacting when you fiddle with buttons, switches, and knobs * * mode switch: modes are changed only when the button is not being * pushed, as button being pushed negates the mode switch response. * for the mode to change, the mode switch must be in the new position * without wavering for at least 3 rounds. this will prevent the * mode from changing by someone fucking around with the button or * when the button is used normally. * * button: is connected to mode switch ADC. if below threshold, then * we can be certain button is pushed. we still wait a debounce * round to ensure button is pushed. our code can fire events on * either button being held or button being released. the actual * push event does not do anything with this code. * * settings knobs: these are used by the settings module which works * with the other modules and the button for setting user settings. * the values are scaled from the ADC value, with bounds being set * on the low and high ends and further scaled for usability. * please read the manual if you want to know what settings do. * * file creation: 20231015 0122 */ #include #include #include "testo.h" #include "userio.h" #include "adc.h" #include "probe.h" #define MODE_SET_LIMIT 60 // 3x worst case expected (1% tol) #define MODE_CHANGE_TICKS 4 // how many samples before switching modes #define MODE_ANALOG_MIN 20 #define BTN_OPEN 0 #define BTN_PUSHED 1 #define BTN_OVERRIDE 2 #ifdef TESTO_REV1 #define SET1_MAX 2199 // 3V net feeding into 1V24 via body diode above this #else #define SET1_MAX 1539 // 1.24Vref #endif static uint8_t mode = 0xff; static uint8_t mode_next; static uint8_t mode_count; static const int16_t mode_targets[] = { MODE_CONT_TARGET, MODE_FUN_TARGET, MODE_DIODE_TARGET }; uint8_t knob[2]; static uint8_t btn = 0; static uint16_t btn_held = 0; void userio_parse() { uint8_t i; int16_t m, w; uint32_t x; // button { // debounce is handled by the fact that we've had to have averaged // about 16ms of measured hold time below the zero threshold. m = adc_avg[ADC_SET_MODE]; if (m < MODE_ANALOG_MIN) { // button is pushed if (btn == BTN_OPEN) btn = 1; if (btn_held != 0xffff) btn_held++; } else if (btn) { // release held count if overridden if (btn == BTN_OVERRIDE) btn_held = 0; // button is released btn = 0; } } // mode if (!btn) { for (i = 0; i < 4; i++) { // clear mode_count if we aren't actively changing modes if (i == 3) { mode_count = 0; break; } // normalize mode selection w = abs(m - mode_targets[i]); // determine if we mode switch if (w < MODE_SET_LIMIT) { // currently in this mode? if so, ignore it if (mode == i) continue; // is the next mode set to this item? if (mode_next == i) { // increment the verification count mode_count++; if (mode_count >= MODE_CHANGE_TICKS) { // we've got enough data to do a change of mode mode = i; mode_count = 0; // MODE SWITCH ACTION IS HANDLED HERE // restart ADC on mode change to update values // to reflect selected measurement mode adc_switch0(); // and set the probe measurement routines // to use the selected mode probe_mode_switch(mode); } } else { // set the next mode to the newly selected mode mode_next = i; mode_count = 0; } break; } } } // knobs { // SET0 is always connected, so just copy and scale it knob[0] = adc_avg[ADC_SET0] >> 4; // SET1/VREFEXT input can be SET1 or VREFEXT, depending on PROBESEL. // only copy if not set to VREFEXT, and only if within valid range if (PROBESEL_PORT->ODR & (1 << PROBESEL_PIN)) { // PROBESEL is high, so SET1 is in use if (adc_avg[ADC_SET1] > SET1_MAX) { // knob is turned too far; warn the user. // TODO } else { x = adc_avg[ADC_SET1] << 12; // maximum possible level x /= SET1_MAX; // normalize to 4096max knob[1] = (x >> 4) & 0xff; // reduce to 8-bit } } } } uint8_t userio_get_mode() { return mode; } /* * returns the button state. * -1 = button is currently being pressed * 0 = button is not being pressed * >0 = button is not being pressed, but was (just?) released and held for X ticks */ int16_t userio_get_btn() { int16_t ret; if (btn == BTN_PUSHED) return -1; if (btn == BTN_OPEN) { if (btn_held) { ret = btn_held; btn_held = 0; return ret; } } return 0; } /* * returns the button state. * 0 = not held * >0 = held for X ticks */ int16_t userio_get_btn_held() { return btn_held; } /* * overrides and disables the next button release event. */ void userio_set_btn_override() { btn = BTN_OVERRIDE; } /* * returns true if the right knob is beyond maximum range. * always returns false on REV2 or later boards. */ uint8_t userio_get_set1_limit() { #ifdef TESTO_REV1 if (adc_avg[ADC_SET1] > SET1_MAX) return 1; #endif return 0; }