summaryrefslogtreecommitdiffstats
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/action.c19
-rw-r--r--quantum/action_util.c25
-rw-r--r--quantum/action_util.h13
-rw-r--r--quantum/audio/audio.c45
-rw-r--r--quantum/backlight/backlight.c1
-rw-r--r--quantum/backlight/backlight_avr.c473
-rw-r--r--quantum/backlight/backlight_chibios.c173
-rw-r--r--quantum/backlight/backlight_driver_common.c3
-rw-r--r--quantum/backlight/backlight_software.c54
-rw-r--r--quantum/backlight/backlight_timer.c179
-rw-r--r--quantum/debounce.h4
-rw-r--r--quantum/debounce/asym_eager_defer_pk.c5
-rw-r--r--quantum/debounce/none.c4
-rw-r--r--quantum/debounce/sym_defer_g.c3
-rw-r--r--quantum/debounce/sym_defer_pk.c3
-rw-r--r--quantum/debounce/sym_defer_pr.c3
-rw-r--r--quantum/debounce/sym_eager_pk.c4
-rw-r--r--quantum/debounce/sym_eager_pr.c4
-rw-r--r--quantum/debounce/tests/debounce_test_common.cpp3
-rw-r--r--quantum/debounce/tests/debounce_test_common.h2
-rw-r--r--quantum/dynamic_keymap.c15
-rw-r--r--quantum/keycode_config.c44
-rw-r--r--quantum/keymap.h20
-rw-r--r--quantum/led.c6
-rw-r--r--quantum/led.h7
-rw-r--r--quantum/led_matrix/led_matrix.c5
-rw-r--r--quantum/led_matrix/led_matrix.h3
-rw-r--r--quantum/mousekey.c68
-rw-r--r--quantum/painter/lvgl/qp_lvgl.c2
-rw-r--r--quantum/painter/qp.c29
-rw-r--r--quantum/painter/qp_comms.c8
-rw-r--r--quantum/painter/qp_draw_circle.c2
-rw-r--r--quantum/painter/qp_draw_core.c6
-rw-r--r--quantum/painter/qp_draw_ellipse.c2
-rw-r--r--quantum/painter/qp_draw_image.c6
-rw-r--r--quantum/painter/qp_draw_text.c8
-rw-r--r--quantum/process_keycode/process_auto_shift.c10
-rw-r--r--quantum/process_keycode/process_auto_shift.h8
-rw-r--r--quantum/process_keycode/process_autocorrect.c74
-rw-r--r--quantum/process_keycode/process_autocorrect.h4
-rw-r--r--quantum/process_keycode/process_dynamic_macro.c117
-rw-r--r--quantum/process_keycode/process_dynamic_macro.h1
-rw-r--r--quantum/process_keycode/process_key_override.c9
-rw-r--r--quantum/quantum.c8
-rw-r--r--quantum/quantum_keycodes.h4
-rw-r--r--quantum/quantum_keycodes_legacy.h3
-rw-r--r--quantum/rgb_matrix/animations/pixel_fractal_anim.h6
-rw-r--r--quantum/rgb_matrix/animations/pixel_rain_anim.h10
-rw-r--r--quantum/rgb_matrix/rgb_matrix.c5
-rw-r--r--quantum/rgb_matrix/rgb_matrix.h3
-rw-r--r--quantum/rgb_matrix/rgb_matrix_drivers.c15
-rw-r--r--quantum/split_common/transactions.c2
-rw-r--r--quantum/via.c99
-rw-r--r--quantum/via.h14
54 files changed, 522 insertions, 1121 deletions
diff --git a/quantum/action.c b/quantum/action.c
index a45e70c557..6368f7398c 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -528,6 +528,13 @@ void process_action(keyrecord_t *record, action_t action) {
unregister_code(action.key.code);
} else {
ac_dprintf("MODS_TAP: No tap: add_mods\n");
+# if defined(RETRO_TAPPING) && defined(DUMMY_MOD_NEUTRALIZER_KEYCODE)
+ // Send a dummy keycode to neutralize flashing modifiers
+ // if the key was held and then released with no interruptions.
+ if (retro_tapping_counter == 2) {
+ neutralize_flashing_modifiers(get_mods());
+ }
+# endif
unregister_mods(mods);
}
}
@@ -882,7 +889,7 @@ __attribute__((weak)) void register_code(uint8_t code) {
} else if (KC_LOCKING_CAPS_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
// Resync: ignore if caps lock already is on
- if (host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK)) return;
+ if (host_keyboard_led_state().caps_lock) return;
# endif
add_key(KC_CAPS_LOCK);
send_keyboard_report();
@@ -892,7 +899,7 @@ __attribute__((weak)) void register_code(uint8_t code) {
} else if (KC_LOCKING_NUM_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
- if (host_keyboard_leds() & (1 << USB_LED_NUM_LOCK)) return;
+ if (host_keyboard_led_state().num_lock) return;
# endif
add_key(KC_NUM_LOCK);
send_keyboard_report();
@@ -902,7 +909,7 @@ __attribute__((weak)) void register_code(uint8_t code) {
} else if (KC_LOCKING_SCROLL_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
- if (host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK)) return;
+ if (host_keyboard_led_state().scroll_lock) return;
# endif
add_key(KC_SCROLL_LOCK);
send_keyboard_report();
@@ -952,7 +959,7 @@ __attribute__((weak)) void unregister_code(uint8_t code) {
} else if (KC_LOCKING_CAPS_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
// Resync: ignore if caps lock already is off
- if (!(host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK))) return;
+ if (!host_keyboard_led_state().caps_lock) return;
# endif
add_key(KC_CAPS_LOCK);
send_keyboard_report();
@@ -961,7 +968,7 @@ __attribute__((weak)) void unregister_code(uint8_t code) {
} else if (KC_LOCKING_NUM_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
- if (!(host_keyboard_leds() & (1 << USB_LED_NUM_LOCK))) return;
+ if (!host_keyboard_led_state().num_lock) return;
# endif
add_key(KC_NUM_LOCK);
send_keyboard_report();
@@ -970,7 +977,7 @@ __attribute__((weak)) void unregister_code(uint8_t code) {
} else if (KC_LOCKING_SCROLL_LOCK == code) {
# ifdef LOCKING_RESYNC_ENABLE
- if (!(host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK))) return;
+ if (!host_keyboard_led_state().scroll_lock) return;
# endif
add_key(KC_SCROLL_LOCK);
send_keyboard_report();
diff --git a/quantum/action_util.c b/quantum/action_util.c
index 361f410d2d..909dea0595 100644
--- a/quantum/action_util.c
+++ b/quantum/action_util.c
@@ -500,3 +500,28 @@ __attribute__((weak)) void oneshot_layer_changed_kb(uint8_t layer) {
uint8_t has_anymod(void) {
return bitpop(real_mods);
}
+
+#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE
+/** \brief Send a dummy keycode in between the register and unregister event of a modifier key, to neutralize the "flashing modifiers" phenomenon.
+ *
+ * \param active_mods 8-bit packed bit-array describing the currently active modifiers (in the format GASCGASC).
+ *
+ * Certain QMK features like key overrides or retro tap must unregister a previously
+ * registered modifier before sending another keycode but this can trigger undesired
+ * keyboard shortcuts if the clean tap of a single modifier key is bound to an action
+ * on the host OS, as is for example the case for the left GUI key on Windows, which
+ * opens the Start Menu when tapped.
+ */
+void neutralize_flashing_modifiers(uint8_t active_mods) {
+ // In most scenarios, the flashing modifiers phenomenon is a problem
+ // only for a subset of modifier masks.
+ const static uint8_t mods_to_neutralize[] = MODS_TO_NEUTRALIZE;
+ const static uint8_t n_mods = ARRAY_SIZE(mods_to_neutralize);
+ for (uint8_t i = 0; i < n_mods; ++i) {
+ if (active_mods == mods_to_neutralize[i]) {
+ tap_code(DUMMY_MOD_NEUTRALIZER_KEYCODE);
+ break;
+ }
+ }
+}
+#endif
diff --git a/quantum/action_util.h b/quantum/action_util.h
index 02f6e9e6df..831caf3c0a 100644
--- a/quantum/action_util.h
+++ b/quantum/action_util.h
@@ -102,6 +102,19 @@ void use_oneshot_swaphands(void);
void clear_oneshot_swaphands(void);
#endif
+#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE
+// KC_A is used as the lowerbound instead of QK_BASIC because the range QK_BASIC...KC_A includes
+// internal keycodes like KC_NO and KC_TRANSPARENT which are unsuitable for use with `tap_code(kc)`.
+# if !(KC_A <= DUMMY_MOD_NEUTRALIZER_KEYCODE && DUMMY_MOD_NEUTRALIZER_KEYCODE <= QK_BASIC_MAX)
+# error "DUMMY_MOD_NEUTRALIZER_KEYCODE must be a basic, unmodified, HID keycode!"
+# endif
+void neutralize_flashing_modifiers(uint8_t active_mods);
+#endif
+#ifndef MODS_TO_NEUTRALIZE
+# define MODS_TO_NEUTRALIZE \
+ { MOD_BIT(KC_LEFT_ALT), MOD_BIT(KC_LEFT_GUI) }
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
index 2570ad9cd1..0300483a93 100644
--- a/quantum/audio/audio.c
+++ b/quantum/audio/audio.c
@@ -547,20 +547,39 @@ void audio_decrease_tempo(uint8_t tempo_change) {
note_tempo -= tempo_change;
}
-// TODO in the int-math version are some bugs; songs sometimes abruptly end - maybe an issue with the timer/system-tick wrapping around?
+/**
+ * Converts from units of 1/64ths of a beat to milliseconds.
+ *
+ * Round-off error is at most 1 millisecond.
+ *
+ * Conversion will never overflow for duration_bpm <= 699, provided that
+ * note_tempo is at least 10. This is quite a long duration, over ten beats.
+ *
+ * Beware that for duration_bpm > 699, the result may overflow uint16_t range
+ * when duration_bpm is large compared to note_tempo:
+ *
+ * duration_bpm * 60 * 1000 / (64 * note_tempo) > UINT16_MAX
+ *
+ * duration_bpm > (2 * 65535 / 1875) * note_tempo
+ * = 69.904 * note_tempo.
+ */
uint16_t audio_duration_to_ms(uint16_t duration_bpm) {
-#if defined(__AVR__)
- // doing int-math saves us some bytes in the overall firmware size, but the intermediate result is less accurate before being cast to/returned as uint
- return ((uint32_t)duration_bpm * 60 * 1000) / (64 * note_tempo);
- // NOTE: beware of uint16_t overflows when note_tempo is low and/or the duration is long
-#else
- return ((float)duration_bpm * 60) / (64 * note_tempo) * 1000;
-#endif
+ return ((uint32_t)duration_bpm * 1875) / ((uint_fast16_t)note_tempo * 2);
}
+
+/**
+ * Converts from units of milliseconds to 1/64ths of a beat.
+ *
+ * Round-off error is at most 1/64th of a beat.
+ *
+ * This conversion never overflows: since duration_ms <= UINT16_MAX = 65535
+ * and note_tempo <= 255, the result is always in uint16_t range:
+ *
+ * duration_ms * 64 * note_tempo / 60 / 1000
+ * <= 65535 * 2 * 255 / 1875
+ * = 17825.52
+ * <= UINT16_MAX.
+ */
uint16_t audio_ms_to_duration(uint16_t duration_ms) {
-#if defined(__AVR__)
- return ((uint32_t)duration_ms * 64 * note_tempo) / 60 / 1000;
-#else
- return ((float)duration_ms * 64 * note_tempo) / 60 / 1000;
-#endif
+ return ((uint32_t)duration_ms * 2 * note_tempo) / 1875;
}
diff --git a/quantum/backlight/backlight.c b/quantum/backlight/backlight.c
index 52ec086bb0..9d9f944f5d 100644
--- a/quantum/backlight/backlight.c
+++ b/quantum/backlight/backlight.c
@@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "quantum.h"
#include "backlight.h"
#include "eeprom.h"
#include "eeconfig.h"
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c
deleted file mode 100644
index 474e0a86f5..0000000000
--- a/quantum/backlight/backlight_avr.c
+++ /dev/null
@@ -1,473 +0,0 @@
-#include "quantum.h"
-#include "backlight.h"
-#include "backlight_driver_common.h"
-#include "debug.h"
-
-// Maximum duty cycle limit
-#ifndef BACKLIGHT_LIMIT_VAL
-# define BACKLIGHT_LIMIT_VAL 255
-#endif
-
-// This logic is a bit complex, we support 3 setups:
-//
-// 1. Hardware PWM when backlight is wired to a PWM pin.
-// Depending on this pin, we use a different output compare unit.
-// 2. Software PWM with hardware timers, but the used timer
-// depends on the Audio setup (Audio wins over Backlight).
-// 3. Full software PWM, driven by the matrix scan, if both timers are used by Audio.
-
-#if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == B5 || BACKLIGHT_PIN == B6 || BACKLIGHT_PIN == B7)
-# define HARDWARE_PWM
-# define ICRx ICR1
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TIMSKx TIMSK1
-# define TOIEx TOIE1
-
-# if BACKLIGHT_PIN == B5
-# define COMxx0 COM1A0
-# define COMxx1 COM1A1
-# define OCRxx OCR1A
-# elif BACKLIGHT_PIN == B6
-# define COMxx0 COM1B0
-# define COMxx1 COM1B1
-# define OCRxx OCR1B
-# elif BACKLIGHT_PIN == B7
-# define COMxx0 COM1C0
-# define COMxx1 COM1C1
-# define OCRxx OCR1C
-# endif
-#elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) && (BACKLIGHT_PIN == C4 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
-# define HARDWARE_PWM
-# define ICRx ICR3
-# define TCCRxA TCCR3A
-# define TCCRxB TCCR3B
-# define TIMERx_OVF_vect TIMER3_OVF_vect
-# define TIMSKx TIMSK3
-# define TOIEx TOIE3
-
-# if BACKLIGHT_PIN == C4
-# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
-# error This MCU has no C4 pin!
-# else
-# define COMxx0 COM3C0
-# define COMxx1 COM3C1
-# define OCRxx OCR3C
-# endif
-# elif BACKLIGHT_PIN == C5
-# if (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
-# error This MCU has no C5 pin!
-# else
-# define COMxx0 COM3B0
-# define COMxx1 COM3B1
-# define OCRxx OCR3B
-# endif
-# elif BACKLIGHT_PIN == C6
-# define COMxx0 COM3A0
-# define COMxx1 COM3A1
-# define OCRxx OCR3A
-# endif
-#elif (defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)) && (BACKLIGHT_PIN == B7 || BACKLIGHT_PIN == C5 || BACKLIGHT_PIN == C6)
-# define HARDWARE_PWM
-# define ICRx ICR1
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TIMSKx TIMSK1
-# define TOIEx TOIE1
-
-# if BACKLIGHT_PIN == B7
-# define COMxx0 COM1C0
-# define COMxx1 COM1C1
-# define OCRxx OCR1C
-# elif BACKLIGHT_PIN == C5
-# define COMxx0 COM1B0
-# define COMxx1 COM1B1
-# define OCRxx OCR1B
-# elif BACKLIGHT_PIN == C6
-# define COMxx0 COM1A0
-# define COMxx1 COM1A1
-# define OCRxx OCR1A
-# endif
-#elif defined(__AVR_ATmega32A__) && (BACKLIGHT_PIN == D4 || BACKLIGHT_PIN == D5)
-# define HARDWARE_PWM
-# define ICRx ICR1
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TIMSKx TIMSK
-# define TOIEx TOIE1
-
-# if BACKLIGHT_PIN == D4
-# define COMxx0 COM1B0
-# define COMxx1 COM1B1
-# define OCRxx OCR1B
-# elif BACKLIGHT_PIN == D5
-# define COMxx0 COM1A0
-# define COMxx1 COM1A1
-# define OCRxx OCR1A
-# endif
-#elif (defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)) && (BACKLIGHT_PIN == B1 || BACKLIGHT_PIN == B2)
-# define HARDWARE_PWM
-# define ICRx ICR1
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# define TIMSKx TIMSK1
-# define TOIEx TOIE1
-
-# if BACKLIGHT_PIN == B1
-# define COMxx0 COM1A0
-# define COMxx1 COM1A1
-# define OCRxx OCR1A
-# elif BACKLIGHT_PIN == B2
-# define COMxx0 COM1B0
-# define COMxx1 COM1B1
-# define OCRxx OCR1B
-# endif
-#elif (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
-// Timer 1 is not in use by Audio feature, Backlight can use it
-# pragma message "Using hardware timer 1 with software PWM"
-# define HARDWARE_PWM
-# define BACKLIGHT_PWM_TIMER
-# define ICRx ICR1
-# define TCCRxA TCCR1A
-# define TCCRxB TCCR1B
-# define TIMERx_COMPA_vect TIMER1_COMPA_vect
-# define TIMERx_OVF_vect TIMER1_OVF_vect
-# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
-# define TIMSKx TIMSK
-# else
-# define TIMSKx TIMSK1
-# endif
-# define TOIEx TOIE1
-
-# define OCIExA OCIE1A
-# define OCRxx OCR1A
-#elif (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6)
-# pragma message "Using hardware timer 3 with software PWM"
-// Timer 3 is not in use by Audio feature, Backlight can use it
-# define HARDWARE_PWM
-# define BACKLIGHT_PWM_TIMER
-# define ICRx ICR1
-# define TCCRxA TCCR3A
-# define TCCRxB TCCR3B
-# define TIMERx_COMPA_vect TIMER3_COMPA_vect
-# define TIMERx_OVF_vect TIMER3_OVF_vect
-# define TIMSKx TIMSK3
-# define TOIEx TOIE3
-
-# define OCIExA OCIE3A
-# define OCRxx OCR3A
-#elif defined(BACKLIGHT_CUSTOM_DRIVER)
-error("Please set 'BACKLIGHT_DRIVER = custom' within rules.mk")
-#else
-error("Please set 'BACKLIGHT_DRIVER = software' within rules.mk")
-#endif
-
-#ifndef BACKLIGHT_PWM_TIMER // pwm through software
-
-static inline void enable_pwm(void) {
-# if BACKLIGHT_ON_STATE == 1
- TCCRxA |= _BV(COMxx1);
-# else
- TCCRxA |= _BV(COMxx1) | _BV(COMxx0);
-# endif
-}
-
-static inline void disable_pwm(void) {
-# if BACKLIGHT_ON_STATE == 1
- TCCRxA &= ~(_BV(COMxx1));
-# else
- TCCRxA &= ~(_BV(COMxx1) | _BV(COMxx0));
-# endif
-}
-
-#endif
-
-#ifdef BACKLIGHT_PWM_TIMER
-
-// The idea of software PWM assisted by hardware timers is the following
-// we use the hardware timer in fast PWM mode like for hardware PWM, but
-// instead of letting the Output Match Comparator control the led pin
-// (which is not possible since the backlight is not wired to PWM pins on the
-// CPU), we do the LED on/off by oursleves.
-// The timer is setup to count up to 0xFFFF, and we set the Output Compare
-// register to the current 16bits backlight level (after CIE correction).
-// This means the CPU will trigger a compare match interrupt when the counter
-// reaches the backlight level, where we turn off the LEDs,
-// but also an overflow interrupt when the counter rolls back to 0,
-// in which we're going to turn on the LEDs.
-// The LED will then be on for OCRxx/0xFFFF time, adjusted every 244Hz,
-// or F_CPU/BACKLIGHT_CUSTOM_RESOLUTION if used.
-
-// Triggered when the counter reaches the OCRx value
-ISR(TIMERx_COMPA_vect) {
- backlight_pins_off();
-}
-
-// Triggered when the counter reaches the TOP value
-// this one triggers at F_CPU/ICRx = 16MHz/65536 =~ 244 Hz
-ISR(TIMERx_OVF_vect) {
-# ifdef BACKLIGHT_BREATHING
- if (is_breathing()) {
- breathing_task();
- }
-# endif
- // for very small values of OCRxx (or backlight level)
- // we can't guarantee this whole code won't execute
- // at the same time as the compare match interrupt
- // which means that we might turn on the leds while
- // trying to turn them off, leading to flickering
- // artifacts (especially while breathing, because breathing_task
- // takes many computation cycles).
- // so better not turn them on while the counter TOP is very low.
- if (OCRxx > ICRx / 250 + 5) {
- backlight_pins_on();
- }
-}
-
-#endif
-
-#define TIMER_TOP 0xFFFFU
-
-// See http://jared.geek.nz/2013/feb/linear-led-pwm
-static uint16_t cie_lightness(uint16_t v) {
- if (v <= (uint32_t)ICRx / 12) // If the value is less than or equal to ~8% of max
- {
- return v / 9; // Same as dividing by 900%
- } else {
- // In the next two lines values are bit-shifted. This is to avoid loosing decimals in integer math.
- uint32_t y = (((uint32_t)v + (uint32_t)ICRx / 6) << 5) / ((uint32_t)ICRx / 6 + ICRx); // If above 8%, add ~16% of max, and normalize with (max + ~16% max)
- uint32_t out = (y * y * y * ICRx) >> 15; // Cube it and undo the bit-shifting. (which is now three times as much due to the cubing)
-
- if (out > ICRx) // Avoid overflows
- {
- out = ICRx;
- }
- return (uint16_t)out;
- }
-}
-
-// rescale the supplied backlight value to be in terms of the value limit // range for val is [0..ICRx]. PWM pin is high while the timer count is below val.
-static uint32_t rescale_limit_val(uint32_t val) {
- return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256;
-}
-
-// range for val is [0..ICRx]. PWM pin is high while the timer count is below val.
-static inline void set_pwm(uint16_t val) {
- OCRxx = val;
-}
-
-void backlight_set(uint8_t level) {
- if (level > BACKLIGHT_LEVELS) level = BACKLIGHT_LEVELS;
-
- if (level == 0) {
-#ifdef BACKLIGHT_PWM_TIMER
- if (OCRxx) {
- TIMSKx &= ~(_BV(OCIExA));
- TIMSKx &= ~(_BV(TOIEx));
- }
-#else
- // Turn off PWM control on backlight pin
- disable_pwm();
-#endif
- backlight_pins_off();
- } else {
-#ifdef BACKLIGHT_PWM_TIMER
- if (!OCRxx) {
- TIMSKx |= _BV(OCIExA);
- TIMSKx |= _BV(TOIEx);
- }
-#else
- // Turn on PWM control of backlight pin
- enable_pwm();
-#endif
- }
- // Set the brightness
- set_pwm(cie_lightness(rescale_limit_val(ICRx * (uint32_t)level / BACKLIGHT_LEVELS)));
-}
-
-void backlight_task(void) {}
-
-#ifdef BACKLIGHT_BREATHING
-
-# define BREATHING_NO_HALT 0
-# define BREATHING_HALT_OFF 1
-# define BREATHING_HALT_ON 2
-# define BREATHING_STEPS 128
-
-static uint8_t breathing_halt = BREATHING_NO_HALT;
-static uint16_t breathing_counter = 0;
-
-static uint8_t breath_scale_counter = 1;
-/* Run the breathing loop at ~120Hz*/
-const uint8_t breathing_ISR_frequency = 120;
-static uint16_t breathing_freq_scale_factor = 2;
-
-# ifdef BACKLIGHT_PWM_TIMER
-static bool breathing = false;
-
-bool is_breathing(void) {
- return breathing;
-}
-
-# define breathing_interrupt_enable() \
- do { \
- breathing = true; \
- } while (0)
-# define breathing_interrupt_disable() \
- do { \
- breathing = false; \
- } while (0)
-# else
-
-bool is_breathing(void) {
- return !!(TIMSKx & _BV(TOIEx));
-}
-
-# define breathing_interrupt_enable() \
- do { \
- TIMSKx |= _BV(TOIEx); \
- } while (0)
-# define breathing_interrupt_disable() \
- do { \
- TIMSKx &= ~_BV(TOIEx); \
- } while (0)
-# endif
-
-# define breathing_min() \
- do { \
- breathing_counter = 0; \
- } while (0)
-# define breathing_max() \
- do { \
- breathing_counter = get_breathing_period() * breathing_ISR_frequency / 2; \
- } while (0)
-
-void breathing_enable(void) {
- breathing_counter = 0;
- breathing_halt = BREATHING_NO_HALT;
- breathing_interrupt_enable();
-}
-
-void breathing_pulse(void) {
- if (get_backlight_level() == 0)
- breathing_min();
- else
- breathing_max();
- breathing_halt = BREATHING_HALT_ON;
- breathing_interrupt_enable();
-}
-
-void breathing_disable(void) {
- breathing_interrupt_disable();
- // Restore backlight level
- backlight_set(get_backlight_level());
-}
-
-void breathing_self_disable(void) {
- if (get_backlight_level() == 0)
- breathing_halt = BREATHING_HALT_OFF;
- else
- breathing_halt = BREATHING_HALT_ON;
-}
-
-/* To generate breathing