diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 69df82f9532..71c803bc21c 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -296,6 +296,16 @@ This command allows you to generate QMK documentation locally. It can be uses fo qmk generate-docs ``` +## `qmk generate-rgb-breathe-table` + +This command generates a lookup table (LUT) header file for the [RGB Lighting](feature_rgblight.md) feature's breathing animation. Place this file in your keyboard or keymap directory as `rgblight_breathe_table.h` to override the default LUT in `quantum/`. + +**Usage**: + +``` +qmk generate-rgb-breathe-table [-q] [-o OUTPUT] [-m MAX] [-c CENTER] +``` + ## `qmk kle2json` This command allows you to convert from raw KLE data to QMK Configurator JSON. It accepts either an absolute file path, or a file name in the current directory. By default it will not overwrite `info.json` if it is already present. Use the `-f` or `--force` flag to overwrite. diff --git a/lib/python/qmk/cli/generate/__init__.py b/lib/python/qmk/cli/generate/__init__.py index 13bd1f09141..f9585bfb5ce 100644 --- a/lib/python/qmk/cli/generate/__init__.py +++ b/lib/python/qmk/cli/generate/__init__.py @@ -1,2 +1,3 @@ from . import api from . import docs +from . import rgb_breathe_table diff --git a/lib/python/qmk/cli/generate/rgb_breathe_table.py b/lib/python/qmk/cli/generate/rgb_breathe_table.py new file mode 100644 index 00000000000..e1c5423ee5a --- /dev/null +++ b/lib/python/qmk/cli/generate/rgb_breathe_table.py @@ -0,0 +1,79 @@ +"""Generate rgblight_breathe_table.h +""" +import math +from argparse import ArgumentTypeError + +from milc import cli + +import qmk.path + + +def breathing_center(value): + value = float(value) + if value >= 1 and value <= 2.7: + return value + else: + raise ArgumentTypeError('Breathing center must be between 1 and 2.7') + + +def breathing_max(value): + value = int(value) + if value in range(0, 256): + return value + else: + raise ArgumentTypeError('Breathing max must be between 0 and 255') + + +@cli.argument('-c', '--center', arg_only=True, type=breathing_center, default=1.85, help='The breathing center value, from 1 to 2.7. Default: 1.85') +@cli.argument('-m', '--max', arg_only=True, type=breathing_max, default=255, help='The breathing maximum value, from 0 to 255. Default: 255') +@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') +@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help='Quiet mode, only output error messages') +@cli.subcommand('Generates an RGB Light breathing table header.') +def generate_rgb_breathe_table(cli): + """Generate a rgblight_breathe_table.h file containing a breathing LUT for RGB Lighting (Underglow) feature. + """ + breathe_values = [0] * 256 + for pos in range(0, 256): + breathe_values[pos] = (int)((math.exp(math.sin((pos/255) * math.pi)) - cli.args.center / math.e) * (cli.args.max / (math.e - 1 / math.e))) # noqa: yapf insists there be no whitespace around / + + values_template = '' + for s in range(0, 3): + step = 1 << s + + values_template += '#if RGBLIGHT_BREATHE_TABLE_SIZE == {}\n'.format(256 >> s) + + for pos in range(0, 256, step): + values_template += ' ' if pos % 8 == 0 else '' + values_template += '0x{:02X}'.format(breathe_values[pos]) + values_template += ',' if (pos + step) < 256 else '' + values_template += '\n' if (pos+step) % 8 == 0 else ' ' # noqa: yapf insists there be no whitespace around + + + values_template += '#endif' + values_template += '\n\n' if s < 2 else '' + + table_template = '''#pragma once + +#define RGBLIGHT_EFFECT_BREATHE_TABLE + +// clang-format off + +// Breathing center: {0:.2f} +// Breathing max: {1:d} + +const uint8_t PROGMEM rgblight_effect_breathe_table[] = {{ +{2} +}}; + +static const int table_scale = 256 / sizeof(rgblight_effect_breathe_table); +'''.format(cli.args.center, cli.args.max, values_template) + + if cli.args.output: + cli.args.output.parent.mkdir(parents=True, exist_ok=True) + if cli.args.output.exists(): + cli.args.output.replace(cli.args.output.name + '.bak') + cli.args.output.write_text(table_template) + + if not cli.args.quiet: + cli.log.info('Wrote header to %s.', cli.args.output) + else: + print(table_template) diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index 99ec5960838..08e80f2c951 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py @@ -190,3 +190,10 @@ def test_clean(): result = check_subcommand('clean', '-a') check_returncode(result) assert result.stdout.count('done') == 2 + + +def test_generate_rgb_breathe_table(): + result = check_subcommand("generate-rgb-breathe-table", "-c", "1.2", "-m", "127") + check_returncode(result) + assert 'Breathing center: 1.2' in result.stdout + assert 'Breathing max: 127' in result.stdout diff --git a/quantum/rgblight_breathe_table.h b/quantum/rgblight_breathe_table.h index a438332bd3a..30245318b6c 100644 --- a/quantum/rgblight_breathe_table.h +++ b/quantum/rgblight_breathe_table.h @@ -1,468 +1,117 @@ -#ifndef RGBLIGHT_EFFECT_BREATHE_TABLE +#pragma once + #define RGBLIGHT_EFFECT_BREATHE_TABLE -const uint8_t rgblight_effect_breathe_table[] PROGMEM = { -/* #define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85 */ -/* #define RGBLIGHT_EFFECT_BREATHE_MAX 255 */ +// clang-format off +// Breathing center: 1.85 +// Breathing max: 255 + +const uint8_t PROGMEM rgblight_effect_breathe_table[] = { #if RGBLIGHT_BREATHE_TABLE_SIZE == 256 - 0x22, - 0x23, - 0x25, - 0x26, - 0x28, - 0x29, - 0x2a, - 0x2c, - 0x2d, - 0x2f, - 0x30, - 0x32, - 0x33, - 0x35, - 0x36, - 0x38, - 0x3a, - 0x3b, - 0x3d, - 0x3e, - 0x40, - 0x42, - 0x43, - 0x45, - 0x47, - 0x49, - 0x4a, - 0x4c, - 0x4e, - 0x50, - 0x51, - 0x53, - 0x55, - 0x57, - 0x59, - 0x5a, - 0x5c, - 0x5e, - 0x60, - 0x62, - 0x64, - 0x66, - 0x68, - 0x69, - 0x6b, - 0x6d, - 0x6f, - 0x71, - 0x73, - 0x75, - 0x77, - 0x79, - 0x7b, - 0x7d, - 0x7f, - 0x81, - 0x83, - 0x85, - 0x87, - 0x89, - 0x8a, - 0x8c, - 0x8e, - 0x90, - 0x92, - 0x94, - 0x96, - 0x98, - 0x9a, - 0x9c, - 0x9e, - 0x9f, - 0xa1, - 0xa3, - 0xa5, - 0xa7, - 0xa8, - 0xaa, - 0xac, - 0xae, - 0xaf, - 0xb1, - 0xb3, - 0xb4, - 0xb6, - 0xb8, - 0xb9, - 0xbb, - 0xbc, - 0xbe, - 0xbf, - 0xc1, - 0xc2, - 0xc3, - 0xc5, - 0xc6, - 0xc7, - 0xc9, - 0xca, - 0xcb, - 0xcc, - 0xcd, - 0xce, - 0xd0, - 0xd1, - 0xd2, - 0xd2, - 0xd3, - 0xd4, - 0xd5, - 0xd6, - 0xd7, - 0xd7, - 0xd8, - 0xd9, - 0xd9, - 0xda, - 0xda, - 0xdb, - 0xdb, - 0xdb, - 0xdc, - 0xdc, - 0xdc, - 0xdc, - 0xdc, - 0xdd, - 0xdd, - 0xdd, - 0xdd, - 0xdc, - 0xdc, - 0xdc, - 0xdc, - 0xdc, - 0xdb, - 0xdb, - 0xdb, - 0xda, - 0xda, - 0xd9, - 0xd9, - 0xd8, - 0xd7, - 0xd7, - 0xd6, - 0xd5, - 0xd4, - 0xd3, - 0xd2, - 0xd2, - 0xd1, - 0xd0, - 0xce, - 0xcd, - 0xcc, - 0xcb, - 0xca, - 0xc9, - 0xc7, - 0xc6, - 0xc5, - 0xc3, - 0xc2, - 0xc1, - 0xbf, - 0xbe, - 0xbc, - 0xbb, - 0xb9, - 0xb8, - 0xb6, - 0xb4, - 0xb3, - 0xb1, - 0xaf, - 0xae, - 0xac, - 0xaa, - 0xa8, - 0xa7, - 0xa5, - 0xa3, - 0xa1, - 0x9f, - 0x9e, - 0x9c, - 0x9a, - 0x98, - 0x96, - 0x94, - 0x92, - 0x90, - 0x8e, - 0x8c, - 0x8a, - 0x89, - 0x87, - 0x85, - 0x83, - 0x81, - 0x7f, - 0x7d, - 0x7b, - 0x79, - 0x77, - 0x75, - 0x73, - 0x71, - 0x6f, - 0x6d, - 0x6b, - 0x69, - 0x68, - 0x66, - 0x64, - 0x62, - 0x60, - 0x5e, - 0x5c, - 0x5a, - 0x59, - 0x57, - 0x55, - 0x53, - 0x51, - 0x50, - 0x4e, - 0x4c, - 0x4a, - 0x49, - 0x47, - 0x45, - 0x43, - 0x42, - 0x40, - 0x3e, - 0x3d, - 0x3b, - 0x3a, - 0x38, - 0x36, - 0x35, - 0x33, - 0x32, - 0x30, - 0x2f, - 0x2d, - 0x2c, - 0x2a, - 0x29, - 0x28, - 0x26, - 0x25, - 0x23, - 0x22 -#endif /* 256 bytes table */ + 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2A, 0x2C, + 0x2D, 0x2F, 0x30, 0x32, 0x33, 0x35, 0x36, 0x38, + 0x3A, 0x3B, 0x3D, 0x3E, 0x40, 0x42, 0x43, 0x45, + 0x47, 0x49, 0x4A, 0x4C, 0x4E, 0x50, 0x51, 0x53, + 0x55, 0x57, 0x59, 0x5A, 0x5C, 0x5E, 0x60, 0x62, + 0x64, 0x66, 0x68, 0x69, 0x6B, 0x6D, 0x6F, 0x71, + 0x73, 0x75, 0x77, 0x79, 0x7B, 0x7D, 0x7F, 0x81, + 0x83, 0x85, 0x87, 0x89, 0x8A, 0x8C, 0x8E, 0x90, + 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E, 0x9F, + 0xA1, 0xA3, 0xA5, 0xA7, 0xA8, 0xAA, 0xAC, 0xAE, + 0xAF, 0xB1, 0xB3, 0xB4, 0xB6, 0xB8, 0xB9, 0xBB, + 0xBC, 0xBE, 0xBF, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, + 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xD0, + 0xD1, 0xD2, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDA, 0xDB, 0xDB, + 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDB, + 0xDB, 0xDB, 0xDA, 0xDA, 0xD9, 0xD9, 0xD8, 0xD7, + 0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD2, 0xD1, + 0xD0, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC7, + 0xC6, 0xC5, 0xC3, 0xC2, 0xC1, 0xBF, 0xBE, 0xBC, + 0xBB, 0xB9, 0xB8, 0xB6, 0xB4, 0xB3, 0xB1, 0xAF, + 0xAE, 0xAC, 0xAA, 0xA8, 0xA7, 0xA5, 0xA3, 0xA1, + 0x9F, 0x9E, 0x9C, 0x9A, 0x98, 0x96, 0x94, 0x92, + 0x90, 0x8E, 0x8C, 0x8A, 0x89, 0x87, 0x85, 0x83, + 0x81, 0x7F, 0x7D, 0x7B, 0x79, 0x77, 0x75, 0x73, + 0x71, 0x6F, 0x6D, 0x6B, 0x69, 0x68, 0x66, 0x64, + 0x62, 0x60, 0x5E, 0x5C, 0x5A, 0x59, 0x57, 0x55, + 0x53, 0x51, 0x50, 0x4E, 0x4C, 0x4A, 0x49, 0x47, + 0x45, 0x43, 0x42, 0x40, 0x3E, 0x3D, 0x3B, 0x3A, + 0x38, 0x36, 0x35, 0x33, 0x32, 0x30, 0x2F, 0x2D, + 0x2C, 0x2A, 0x29, 0x28, 0x26, 0x25, 0x23, 0x22 +#endif #if RGBLIGHT_BREATHE_TABLE_SIZE == 128 - 0x22, - 0x25, - 0x28, - 0x2a, - 0x2d, - 0x30, - 0x33, - 0x36, - 0x3a, - 0x3d, - 0x40, - 0x43, - 0x47, - 0x4a, - 0x4e, - 0x51, - 0x55, - 0x59, - 0x5c, - 0x60, - 0x64, - 0x68, - 0x6b, - 0x6f, - 0x73, - 0x77, - 0x7b, - 0x7f, - 0x83, - 0x87, - 0x8a, - 0x8e, - 0x92, - 0x96, - 0x9a, - 0x9e, - 0xa1, - 0xa5, - 0xa8, - 0xac, - 0xaf, - 0xb3, - 0xb6, - 0xb9, - 0xbc, - 0xbf, - 0xc2, - 0xc5, - 0xc7, - 0xca, - 0xcc, - 0xce, - 0xd1, - 0xd2, - 0xd4, - 0xd6, - 0xd7, - 0xd9, - 0xda, - 0xdb, - 0xdb, - 0xdc, - 0xdc, - 0xdd, - 0xdd, - 0xdc, - 0xdc, - 0xdc, - 0xdb, - 0xda, - 0xd9, - 0xd8, - 0xd7, - 0xd5, - 0xd3, - 0xd2, - 0xd0, - 0xcd, - 0xcb, - 0xc9, - 0xc6, - 0xc3, - 0xc1, - 0xbe, - 0xbb, - 0xb8, - 0xb4, - 0xb1, - 0xae, - 0xaa, - 0xa7, - 0xa3, - 0x9f, - 0x9c, - 0x98, - 0x94, - 0x90, - 0x8c, - 0x89, - 0x85, - 0x81, - 0x7d, - 0x79, - 0x75, - 0x71, - 0x6d, - 0x69, - 0x66, - 0x62, - 0x5e, - 0x5a, - 0x57, - 0x53, - 0x50, - 0x4c, - 0x49, - 0x45, - 0x42, - 0x3e, - 0x3b, - 0x38, - 0x35, - 0x32, - 0x2f, - 0x2c, - 0x29, - 0x26, - 0x23 -#endif /* 128 bytes table */ + 0x22, 0x25, 0x28, 0x2A, + 0x2D, 0x30, 0x33, 0x36, + 0x3A, 0x3D, 0x40, 0x43, + 0x47, 0x4A, 0x4E, 0x51, + 0x55, 0x59, 0x5C, 0x60, + 0x64, 0x68, 0x6B, 0x6F, + 0x73, 0x77, 0x7B, 0x7F, + 0x83, 0x87, 0x8A, 0x8E, + 0x92, 0x96, 0x9A, 0x9E, + 0xA1, 0xA5, 0xA8, 0xAC, + 0xAF, 0xB3, 0xB6, 0xB9, + 0xBC, 0xBF, 0xC2, 0xC5, + 0xC7, 0xCA, 0xCC, 0xCE, + 0xD1, 0xD2, 0xD4, 0xD6, + 0xD7, 0xD9, 0xDA, 0xDB, + 0xDB, 0xDC, 0xDC, 0xDD, + 0xDD, 0xDC, 0xDC, 0xDC, + 0xDB, 0xDA, 0xD9, 0xD8, + 0xD7, 0xD5, 0xD3, 0xD2, + 0xD0, 0xCD, 0xCB, 0xC9, + 0xC6, 0xC3, 0xC1, 0xBE, + 0xBB, 0xB8, 0xB4, 0xB1, + 0xAE, 0xAA, 0xA7, 0xA3, + 0x9F, 0x9C, 0x98, 0x94, + 0x90, 0x8C, 0x89, 0x85, + 0x81, 0x7D, 0x79, 0x75, + 0x71, 0x6D, 0x69, 0x66, + 0x62, 0x5E, 0x5A, 0x57, + 0x53, 0x50, 0x4C, 0x49, + 0x45, 0x42, 0x3E, 0x3B, + 0x38, 0x35, 0x32, 0x2F, + 0x2C, 0x29, 0x26, 0x23 +#endif #if RGBLIGHT_BREATHE_TABLE_SIZE == 64 - 0x22, - 0x28, - 0x2d, - 0x33, - 0x3a, - 0x40, - 0x47, - 0x4e, - 0x55, - 0x5c, - 0x64, - 0x6b, - 0x73, - 0x7b, - 0x83, - 0x8a, - 0x92, - 0x9a, - 0xa1, - 0xa8, - 0xaf, - 0xb6, - 0xbc, - 0xc2, - 0xc7, - 0xcc, - 0xd1, - 0xd4, - 0xd7, - 0xda, - 0xdb, - 0xdc, - 0xdd, - 0xdc, - 0xdb, - 0xd9, - 0xd7, - 0xd3, - 0xd0, - 0xcb, - 0xc6, - 0xc1, - 0xbb, - 0xb4, - 0xae, - 0xa7, - 0x9f, - 0x98, - 0x90, - 0x89, - 0x81, - 0x79, - 0x71, - 0x69, - 0x62, - 0x5a, - 0x53, - 0x4c, - 0x45, - 0x3e, - 0x38, - 0x32, - 0x2c, - 0x26 -#endif /* 64 bytes table */ + 0x22, 0x28, + 0x2D, 0x33, + 0x3A, 0x40, + 0x47, 0x4E, + 0x55, 0x5C, + 0x64, 0x6B, + 0x73, 0x7B, + 0x83, 0x8A, + 0x92, 0x9A, + 0xA1, 0xA8, + 0xAF, 0xB6, + 0xBC, 0xC2, + 0xC7, 0xCC, + 0xD1, 0xD4, + 0xD7, 0xDA, + 0xDB, 0xDC, + 0xDD, 0xDC, + 0xDB, 0xD9, + 0xD7, 0xD3, + 0xD0, 0xCB, + 0xC6, 0xC1, + 0xBB, 0xB4, + 0xAE, 0xA7, + 0x9F, 0x98, + 0x90, 0x89, + 0x81, 0x79, + 0x71, 0x69, + 0x62, 0x5A, + 0x53, 0x4C, + 0x45, 0x3E, + 0x38, 0x32, + 0x2C, 0x26 +#endif }; static const int table_scale = 256 / sizeof(rgblight_effect_breathe_table); - -#endif /* RGBLIGHT_EFFECT_BREATHE_TABLE */ diff --git a/util/rgblight_breathing_table_calc.c b/util/rgblight_breathing_table_calc.c deleted file mode 100644 index fc4d49ea587..00000000000 --- a/util/rgblight_breathing_table_calc.c +++ /dev/null @@ -1,49 +0,0 @@ -// -// calculate rgblight_effect_breathe_table[] values -// -// this is host program for quantum/rgblight.c:void rgblight_effect_breathing(); -// -// example: -// $ edit util/rgblight_breathing_table_calc.c -// $ cc -o util/rgblight_breathing_table_calc util/rgblight_breathing_table_calc.c -// $ ./util/rgblight_breathing_table_calc > keyboards/KEYBOARD_NAME/keymaps/KEYMAP_NAME/rgblight_breathe_table.h -// -#include -#include -#include - -/// customize breeathing effect part /////////////////////////// -#define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85 // 1 to 2.7 -#define RGBLIGHT_EFFECT_BREATHE_MAX 255 // 0 to 255 -//////////////////////////////////////////////////////////////// - -int main(void) { - int pos, step; - int table[256]; - for (pos = 0; pos < 256; pos ++ ) { - table[pos] = (uint8_t)( - (exp(sin((pos/255.0)*M_PI))- RGBLIGHT_EFFECT_BREATHE_CENTER/M_E) - * (RGBLIGHT_EFFECT_BREATHE_MAX/(M_E-1/M_E)) - ); - } - printf("#ifndef RGBLIGHT_EFFECT_BREATHE_TABLE\n"); - printf("#define RGBLIGHT_EFFECT_BREATHE_TABLE\n\n"); - printf("const uint8_t rgblight_effect_breathe_table[] PROGMEM = {\n"); - printf(" /* #define RGBLIGHT_EFFECT_BREATHE_CENTER %.2f */\n", RGBLIGHT_EFFECT_BREATHE_CENTER); - printf(" /* #define RGBLIGHT_EFFECT_BREATHE_MAX %d */\n", RGBLIGHT_EFFECT_BREATHE_MAX); - - for (int s = 0, step = (1<=256?"":"," ); - if ((pos+step) % 8 == 0) - printf("\n"); - } - printf(" #endif /* %d bytes table */\n", s == 0 ? 256:(s== 1 ? 128: 64)); - } - printf("};\n"); - printf("\nstatic const int table_scale = 256/sizeof(rgblight_effect_breathe_table);\n"); - printf("\n#endif /* RGBLIGHT_EFFECT_BREATHE_TABLE */\n"); - return 0; -}