sc7-testo-firmware/src/userio.c

217 lines
4.9 KiB
C

/*
* 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 <stdint.h>
#include <stdlib.h>
#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;
}