qmk

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.z3bra.org/qmk.git
Log | Files | Refs | Submodules | LICENSE

commit 17e7762de7e3fdfc61c20aa61022f47370630c6a
parent e1e08a494bf9ea46e1385559df76d5f49b8e9087
Author: Alex Ong <the.onga@gmail.com>
Date:   Thu,  4 Apr 2019 08:45:55 +1100

Eager Per Row Debouncing added (added to Ergodox) (#5498)

* Implemented Eager Per Row debouncing algorithm.

Good for when fingers can only press one row at a time (e.g. when keyboard is wired so that "rows" are vertical)

* Added documentation for eager_pr

* Ported ergodox_ez to eager_pr debouncing.

* Removed check for changes in matrix_scan.

* Added further clarification in docs.

* Accidental merge with ergodox_ez

* Small cleanup in eager_pr

* Forgot to debounce_init - this would probably cause seg-faults.

Diffstat:
docs/feature_debounce_type.md | 5++++-
keyboards/ergodox_ez/matrix.c | 458++++++++++++++++++++++++++++++++++---------------------------------------------
keyboards/ergodox_ez/rules.mk | 1+
quantum/debounce/eager_pr.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
quantum/debounce/readme.md | 2+-
5 files changed, 302 insertions(+), 264 deletions(-)

diff --git a/docs/feature_debounce_type.md b/docs/feature_debounce_type.md @@ -33,7 +33,10 @@ The debounce code is compatible with split keyboards. # Changing between included debouncing methods You can either use your own code, by including your own debounce.c, or switch to another included one. Included debounce methods are: -* eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` millseconds of no further input for that key +* eager_pr - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE_DELAY``` milliseconds of no further input for that row. +For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be +appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use. +* eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` milliseconds of no further input for that key * sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed. diff --git a/keyboards/ergodox_ez/matrix.c b/keyboards/ergodox_ez/matrix.c @@ -33,14 +33,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "debug.h" #include "util.h" #include "matrix.h" +#include "debounce.h" #include QMK_KEYBOARD_H #ifdef DEBUG_MATRIX_SCAN_RATE -#include "timer.h" +# include "timer.h" #endif /* - * This constant define not debouncing time in msecs, but amount of matrix - * scan loops which should be made to get stable debounced results. + * This constant define not debouncing time in msecs, assuming eager_pr. * * On Ergodox matrix scan rate is relatively low, because of slow I2C. * Now it's only 317 scans/second, or about 3.15 msec/scan. @@ -52,26 +52,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef DEBOUNCE -# define DEBOUNCE 5 +# define DEBOUNCE 5 #endif /* matrix state(1:on, 0:off) */ -static matrix_row_t matrix[MATRIX_ROWS]; -/* - * matrix state(1:on, 0:off) - * contains the raw values without debounce filtering of the last read cycle. - */ -static matrix_row_t raw_matrix[MATRIX_ROWS]; - -// Debouncing: store for each key the number of scans until it's eligible to -// change. When scanning the matrix, ignore any changes in keys that have -// already changed in the last DEBOUNCE scans. -static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS]; +static matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values +static matrix_row_t matrix[MATRIX_ROWS]; // debounced values static matrix_row_t read_cols(uint8_t row); -static void init_cols(void); -static void unselect_rows(void); -static void select_row(uint8_t row); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); static uint8_t mcp23018_reset_loop; // static uint16_t mcp23018_reset_loop; @@ -81,197 +72,137 @@ uint32_t matrix_timer; uint32_t matrix_scan_count; #endif +__attribute__((weak)) void matrix_init_user(void) {} -__attribute__ ((weak)) -void matrix_init_user(void) {} +__attribute__((weak)) void matrix_scan_user(void) {} -__attribute__ ((weak)) -void matrix_scan_user(void) {} +__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); } -__attribute__ ((weak)) -void matrix_init_kb(void) { - matrix_init_user(); -} +__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); } -__attribute__ ((weak)) -void matrix_scan_kb(void) { - matrix_scan_user(); -} - -inline -uint8_t matrix_rows(void) -{ - return MATRIX_ROWS; -} +inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } -inline -uint8_t matrix_cols(void) -{ - return MATRIX_COLS; -} +inline uint8_t matrix_cols(void) { return MATRIX_COLS; } -void matrix_init(void) -{ - // initialize row and col +void matrix_init(void) { + // initialize row and col - mcp23018_status = init_mcp23018(); + mcp23018_status = init_mcp23018(); + unselect_rows(); + init_cols(); - unselect_rows(); - init_cols(); - - // initialize matrix state: all keys off - for (uint8_t i=0; i < MATRIX_ROWS; i++) { - matrix[i] = 0; - raw_matrix[i] = 0; - for (uint8_t j=0; j < MATRIX_COLS; ++j) { - debounce_matrix[i * MATRIX_COLS + j] = 0; - } - } + // initialize matrix state: all keys off + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + raw_matrix[i] = 0; + } #ifdef DEBUG_MATRIX_SCAN_RATE - matrix_timer = timer_read32(); - matrix_scan_count = 0; + matrix_timer = timer_read32(); + matrix_scan_count = 0; #endif - - matrix_init_quantum(); - + debounce_init(MATRIX_ROWS); + matrix_init_quantum(); } void matrix_power_up(void) { - mcp23018_status = init_mcp23018(); + mcp23018_status = init_mcp23018(); - unselect_rows(); - init_cols(); + unselect_rows(); + init_cols(); - // initialize matrix state: all keys off - for (uint8_t i=0; i < MATRIX_ROWS; i++) { - matrix[i] = 0; - } + // initialize matrix state: all keys off + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + } #ifdef DEBUG_MATRIX_SCAN_RATE - matrix_timer = timer_read32(); - matrix_scan_count = 0; + matrix_timer = timer_read32(); + matrix_scan_count = 0; #endif } -// Returns a matrix_row_t whose bits are set if the corresponding key should be -// eligible to change in this scan. -matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) { - matrix_row_t result = 0; - matrix_row_t change = rawcols ^ raw_matrix[row]; - raw_matrix[row] = rawcols; - for (uint8_t i = 0; i < MATRIX_COLS; ++i) { - if (debounce_matrix[row * MATRIX_COLS + i]) { - --debounce_matrix[row * MATRIX_COLS + i]; - } else { - result |= (1 << i); - } - if (change & (1 << i)) { - debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE; +uint8_t matrix_scan(void) { + if (mcp23018_status) { // if there was an error + if (++mcp23018_reset_loop == 0) { + // if (++mcp23018_reset_loop >= 1300) { + // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans + // this will be approx bit more frequent than once per second + print("trying to reset mcp23018\n"); + mcp23018_status = init_mcp23018(); + if (mcp23018_status) { + print("left side not responding\n"); + } else { + print("left side attached\n"); + ergodox_blink_all_leds(); + } } } - return result; -} - -matrix_row_t debounce_read_cols(uint8_t row) { - // Read the row without debouncing filtering and store it for later usage. - matrix_row_t cols = read_cols(row); - // Get the Debounce mask. - matrix_row_t mask = debounce_mask(cols, row); - // debounce the row and return the result. - return (cols & mask) | (matrix[row] & ~mask);; -} - -uint8_t matrix_scan(void) -{ - if (mcp23018_status) { // if there was an error - if (++mcp23018_reset_loop == 0) { - // if (++mcp23018_reset_loop >= 1300) { - // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans - // this will be approx bit more frequent than once per second - print("trying to reset mcp23018\n"); - mcp23018_status = init_mcp23018(); - if (mcp23018_status) { - print("left side not responding\n"); - } else { - print("left side attached\n"); - ergodox_blink_all_leds(); - } - } - } #ifdef DEBUG_MATRIX_SCAN_RATE - matrix_scan_count++; + matrix_scan_count++; - uint32_t timer_now = timer_read32(); - if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) { - print("matrix scan frequency: "); - pdec(matrix_scan_count); - print("\n"); + uint32_t timer_now = timer_read32(); + if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) { + print("matrix scan frequency: "); + pdec(matrix_scan_count); + print("\n"); - matrix_timer = timer_now; - matrix_scan_count = 0; - } + matrix_timer = timer_now; + matrix_scan_count = 0; + } #endif #ifdef LEFT_LEDS - mcp23018_status = ergodox_left_leds_update(); -#endif // LEFT_LEDS - for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { - select_row(i); - // and select on left hand - select_row(i + MATRIX_ROWS_PER_SIDE); - // we don't need a 30us delay anymore, because selecting a - // left-hand row requires more than 30us for i2c. - - // grab cols from left hand - matrix[i] = debounce_read_cols(i); - // grab cols from right hand - matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE); - - unselect_rows(); - } - - matrix_scan_quantum(); + mcp23018_status = ergodox_left_leds_update(); +#endif // LEFT_LEDS + for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { + // select rows from left and right hands + select_row(i); + select_row(i + MATRIX_ROWS_PER_SIDE); + + // we don't need a 30us delay anymore, because selecting a + // left-hand row requires more than 30us for i2c. + + // grab left + right cols. + raw_matrix[i] = read_cols(i); + raw_matrix[i+MATRIX_ROWS_PER_SIDE] = read_cols(i+MATRIX_ROWS_PER_SIDE); + + unselect_rows(); + } + + debounce(raw_matrix, matrix, MATRIX_ROWS, true); + matrix_scan_quantum(); - return 1; + return 1; } -bool matrix_is_modified(void) // deprecated and evidently not called. +bool matrix_is_modified(void) // deprecated and evidently not called. { - return true; + return true; } -inline -bool matrix_is_on(uint8_t row, uint8_t col) -{ - return (matrix[row] & ((matrix_row_t)1<<col)); -} +inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); } -inline -matrix_row_t matrix_get_row(uint8_t row) -{ - return matrix[row]; -} +inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; } -void matrix_print(void) -{ - print("\nr/c 0123456789ABCDEF\n"); - for (uint8_t row = 0; row < MATRIX_ROWS; row++) { - phex(row); print(": "); - pbin_reverse16(matrix_get_row(row)); - print("\n"); - } +void matrix_print(void) { + print("\nr/c 0123456789ABCDEF\n"); + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); + print(": "); + pbin_reverse16(matrix_get_row(row)); + print("\n"); + } } -uint8_t matrix_key_count(void) -{ - uint8_t count = 0; - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - count += bitpop16(matrix[i]); - } - return count; +uint8_t matrix_key_count(void) { + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += bitpop16(matrix[i]); + } + return count; } /* Column pin configuration @@ -284,43 +215,45 @@ uint8_t matrix_key_count(void) * col: 0 1 2 3 4 5 * pin: B5 B4 B3 B2 B1 B0 */ -static void init_cols(void) -{ - // init on mcp23018 - // not needed, already done as part of init_mcp23018() - - // init on teensy - // Input with pull-up(DDR:0, PORT:1) - DDRF &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); - PORTF |= (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0); +static void init_cols(void) { + // init on mcp23018 + // not needed, already done as part of init_mcp23018() + + // init on teensy + // Input with pull-up(DDR:0, PORT:1) + DDRF &= ~(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0); + PORTF |= (1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0); } -static matrix_row_t read_cols(uint8_t row) -{ - if (row < 7) { - if (mcp23018_status) { // if there was an error - return 0; - } else { - uint8_t data = 0; - mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; - mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; - mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; - mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status < 0) goto out; - data = ~((uint8_t)mcp23018_status); - mcp23018_status = I2C_STATUS_SUCCESS; - out: - i2c_stop(); - return data; - } +static matrix_row_t read_cols(uint8_t row) { + if (row < 7) { + if (mcp23018_status) { // if there was an error + return 0; } else { - /* read from teensy - * bitmask is 0b11110011, but we want those all - * in the lower six bits. - * we'll return 1s for the top two, but that's harmless. - */ - - return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2)); + uint8_t data = 0; + mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status) goto out; + mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status) goto out; + mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status < 0) goto out; + data = ~((uint8_t)mcp23018_status); + mcp23018_status = I2C_STATUS_SUCCESS; + out: + i2c_stop(); + return data; } + } else { + /* read from teensy + * bitmask is 0b11110011, but we want those all + * in the lower six bits. + * we'll return 1s for the top two, but that's harmless. + */ + + return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2)); + } } /* Row pin configuration @@ -333,69 +266,70 @@ static matrix_row_t read_cols(uint8_t row) * row: 0 1 2 3 4 5 6 * pin: A0 A1 A2 A3 A4 A5 A6 */ -static void unselect_rows(void) -{ - // no need to unselect on mcp23018, because the select step sets all - // the other row bits high, and it's not changing to a different - // direction - - // unselect on teensy - // Hi-Z(DDR:0, PORT:0) to unselect - DDRB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); - PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3); - DDRD &= ~(1<<2 | 1<<3); - PORTD &= ~(1<<2 | 1<<3); - DDRC &= ~(1<<6); - PORTC &= ~(1<<6); +static void unselect_rows(void) { + // no need to unselect on mcp23018, because the select step sets all + // the other row bits high, and it's not changing to a different + // direction + + // unselect on teensy + // Hi-Z(DDR:0, PORT:0) to unselect + DDRB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3); + PORTB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3); + DDRD &= ~(1 << 2 | 1 << 3); + PORTD &= ~(1 << 2 | 1 << 3); + DDRC &= ~(1 << 6); + PORTC &= ~(1 << 6); } -static void select_row(uint8_t row) -{ - if (row < 7) { - // select on mcp23018 - if (mcp23018_status) { // if there was an error - // do nothing - } else { - // set active row low : 0 - // set other rows hi-Z : 1 - mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; - mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; - mcp23018_status = i2c_write(0xFF & ~(1<<row), ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out; - out: - i2c_stop(); - } +static void select_row(uint8_t row) { + if (row < 7) { + // select on mcp23018 + if (mcp23018_status) { // if there was an error + // do nothing } else { - // select on teensy - // Output low(DDR:1, PORT:0) to select - switch (row) { - case 7: - DDRB |= (1<<0); - PORTB &= ~(1<<0); - break; - case 8: - DDRB |= (1<<1); - PORTB &= ~(1<<1); - break; - case 9: - DDRB |= (1<<2); - PORTB &= ~(1<<2); - break; - case 10: - DDRB |= (1<<3); - PORTB &= ~(1<<3); - break; - case 11: - DDRD |= (1<<2); - PORTD &= ~(1<<2); - break; - case 12: - DDRD |= (1<<3); - PORTD &= ~(1<<3); - break; - case 13: - DDRC |= (1<<6); - PORTC &= ~(1<<6); - break; - } + // set active row low : 0 + // set other rows hi-Z : 1 + mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status) goto out; + mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status) goto out; + mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT); + if (mcp23018_status) goto out; + out: + i2c_stop(); + } + } else { + // select on teensy + // Output low(DDR:1, PORT:0) to select + switch (row) { + case 7: + DDRB |= (1 << 0); + PORTB &= ~(1 << 0); + break; + case 8: + DDRB |= (1 << 1); + PORTB &= ~(1 << 1); + break; + case 9: + DDRB |= (1 << 2); + PORTB &= ~(1 << 2); + break; + case 10: + DDRB |= (1 << 3); + PORTB &= ~(1 << 3); + break; + case 11: + DDRD |= (1 << 2); + PORTD &= ~(1 << 2); + break; + case 12: + DDRD |= (1 << 3); + PORTD &= ~(1 << 3); + break; + case 13: + DDRC |= (1 << 6); + PORTC &= ~(1 << 6); + break; } + } } diff --git a/keyboards/ergodox_ez/rules.mk b/keyboards/ergodox_ez/rules.mk @@ -83,6 +83,7 @@ SLEEP_LED_ENABLE = no API_SYSEX_ENABLE = no RGBLIGHT_ENABLE = yes RGB_MATRIX_ENABLE = no # enable later +DEBOUNCE_TYPE = eager_pr ifeq ($(strip $(RGB_MATRIX_ENABLE)), no) SRC += i2c_master.c diff --git a/quantum/debounce/eager_pr.c b/quantum/debounce/eager_pr.c @@ -0,0 +1,100 @@ +/* +Copyright 2019 Alex Ong<the.onga@gmail.com> +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +Basic per-row algorithm. Uses an 8-bit counter per row. +After pressing a key, it immediately changes state, and sets a counter. +No further inputs are accepted until DEBOUNCE milliseconds have occurred. +*/ + +#include "matrix.h" +#include "timer.h" +#include "quantum.h" +#include <stdlib.h> + +#ifndef DEBOUNCE + #define DEBOUNCE 5 +#endif + + +#define debounce_counter_t uint8_t + +static debounce_counter_t *debounce_counters; + +#define DEBOUNCE_ELAPSED 251 +#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1) + +void update_debounce_counters(uint8_t num_rows, uint8_t current_time); +void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time); + +//we use num_rows rather than MATRIX_ROWS to support split keyboards +void debounce_init(uint8_t num_rows) +{ + debounce_counters = (debounce_counter_t*)malloc(num_rows*sizeof(debounce_counter_t)); + for (uint8_t r = 0; r < num_rows; r++) + { + debounce_counters[r] = DEBOUNCE_ELAPSED; + } +} + +void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) +{ + uint8_t current_time = timer_read() % MAX_DEBOUNCE; + update_debounce_counters(num_rows, current_time); + transfer_matrix_values(raw, cooked, num_rows, current_time); +} + +//If the current time is > debounce counter, set the counter to enable input. +void update_debounce_counters(uint8_t num_rows, uint8_t current_time) +{ + debounce_counter_t *debounce_pointer = debounce_counters; + for (uint8_t row = 0; row < num_rows; row++) + { + if (*debounce_pointer != DEBOUNCE_ELAPSED) + { + if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) { + *debounce_pointer = DEBOUNCE_ELAPSED; + } + } + debounce_pointer++; + } +} + +// upload from raw_matrix to final matrix; +void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) +{ + debounce_counter_t *debounce_pointer = debounce_counters; + for (uint8_t row = 0; row < num_rows; row++) + { + matrix_row_t existing_row = cooked[row]; + matrix_row_t raw_row = raw[row]; + + //determine new value basd on debounce pointer + raw value + if (*debounce_pointer == DEBOUNCE_ELAPSED && + (existing_row != raw_row)) + { + *debounce_pointer = current_time; + existing_row = raw_row; + } + cooked[row] = existing_row; + + debounce_pointer++; + } +} + +bool debounce_active(void) +{ + return true; +} + diff --git a/quantum/debounce/readme.md b/quantum/debounce/readme.md @@ -22,7 +22,7 @@ Here are a few that could be implemented: sym_g.c sym_pk.c sym_pr.c -sym_pr_cycles.c //currently used in ergo-dox +sym_pr_cycles.c eager_g.c eager_pk.c eager_pr.c //could be used in ergo-dox!