217 lines
4.9 KiB
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;
|
|
} |