|
|
@@ -0,0 +1,113 @@
|
|
|
+// Copyright 2023 QMK
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
+#include "potentiometer.h"
|
|
|
+#include "gpio.h"
|
|
|
+#include "util.h"
|
|
|
+#include "timer.h"
|
|
|
+#include "analog.h"
|
|
|
+
|
|
|
+#ifndef POTENTIOMETER_THROTTLE_MS
|
|
|
+# define POTENTIOMETER_THROTTLE_MS 1
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifndef POTENTIOMETER_OUTPUT_MIN_VALUE
|
|
|
+# define POTENTIOMETER_OUTPUT_MIN_VALUE 0
|
|
|
+#endif
|
|
|
+#ifndef POTENTIOMETER_OUTPUT_MAX_VALUE
|
|
|
+# define POTENTIOMETER_OUTPUT_MAX_VALUE 127
|
|
|
+#endif
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+// ADC Driver
|
|
|
+
|
|
|
+// Matches default adc range
|
|
|
+#ifndef POTENTIOMETER_RAW_MIN_VALUE
|
|
|
+# define POTENTIOMETER_RAW_MIN_VALUE 0
|
|
|
+#endif
|
|
|
+#ifndef POTENTIOMETER_RAW_MAX_VALUE
|
|
|
+# define POTENTIOMETER_RAW_MAX_VALUE (1 << 10)
|
|
|
+#endif
|
|
|
+
|
|
|
+static pin_t potentiometer_pads[] = POTENTIOMETER_PINS;
|
|
|
+#define NUM_POTENTIOMETERS (ARRAY_SIZE(potentiometer_pads))
|
|
|
+
|
|
|
+__attribute__((weak)) void potentiometer_driver_init(void) {
|
|
|
+ // do nothing
|
|
|
+}
|
|
|
+
|
|
|
+__attribute__((weak)) uint16_t potentiometer_driver_sample(uint8_t index) {
|
|
|
+ return analogReadPin(potentiometer_pads[index]);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+// Callbacks
|
|
|
+
|
|
|
+__attribute__((weak)) bool potentiometer_update_user(uint8_t index, uint16_t value) {
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+__attribute__((weak)) bool potentiometer_update_kb(uint8_t index, uint16_t value) {
|
|
|
+ return potentiometer_update_user(index, value);
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+// Default scanning routine
|
|
|
+
|
|
|
+__attribute__((weak)) uint16_t potentiometer_map(uint8_t index, uint16_t value) {
|
|
|
+ (void)index;
|
|
|
+
|
|
|
+ uint32_t a = POTENTIOMETER_OUTPUT_MIN_VALUE;
|
|
|
+ uint32_t b = POTENTIOMETER_OUTPUT_MAX_VALUE;
|
|
|
+ uint32_t min = POTENTIOMETER_RAW_MIN_VALUE;
|
|
|
+ uint32_t max = POTENTIOMETER_RAW_MAX_VALUE;
|
|
|
+
|
|
|
+ // Scale value to min/max using the adc range
|
|
|
+ return ((b - a) * (value - min) / (max - min)) + a;
|
|
|
+}
|
|
|
+
|
|
|
+__attribute__((weak)) bool potentiometer_filter(uint8_t index, uint16_t value) {
|
|
|
+ // ADC currently limited to max of 12 bits - init to max 16 ensures
|
|
|
+ // we can correctly capture even a raw first sample at max adc bounds
|
|
|
+ static uint16_t potentiometer_state[NUM_POTENTIOMETERS] = {UINT16_MAX};
|
|
|
+
|
|
|
+ if (value == potentiometer_state[index]) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ potentiometer_state[index] = value;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+__attribute__((weak)) bool potentiometer_throttle_task(void) {
|
|
|
+#if (POTENTIOMETER_THROTTLE_MS > 0)
|
|
|
+ static uint32_t last_exec = 0;
|
|
|
+ if (timer_elapsed32(last_exec) < POTENTIOMETER_THROTTLE_MS) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ last_exec = timer_read32();
|
|
|
+#endif
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void potentiometer_init(void) {
|
|
|
+ potentiometer_driver_init();
|
|
|
+}
|
|
|
+
|
|
|
+bool potentiometer_task(void) {
|
|
|
+ if (!potentiometer_throttle_task()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool changed = false;
|
|
|
+ for (uint8_t index = 0; index < NUM_POTENTIOMETERS; index++) {
|
|
|
+ uint16_t raw = potentiometer_driver_sample(index);
|
|
|
+ uint16_t value = potentiometer_map(index, raw);
|
|
|
+ if (potentiometer_filter(index, value)) {
|
|
|
+ changed |= true;
|
|
|
+
|
|
|
+ potentiometer_update_kb(index, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return changed;
|
|
|
+}
|