Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
e7d4bc5291 | |||
c6ea96ab43 | |||
63d5c947d3 | |||
466ee76423 | |||
d678724ca8 | |||
14b7602a65 | |||
46dca121fd | |||
1b4ad6b4ae | |||
ccc87421e7 | |||
303f425c6b | |||
9e5676650e | |||
06e5f9b25e | |||
280c10cb09 | |||
24efce0eca | |||
c9108f4b37 | |||
824e48f294 | |||
50b5c6ad72 | |||
5170398479 | |||
2e88f77675 | |||
1ef819ba96 | |||
72ea1fd972 | |||
e6be4484e9 | |||
1806509ad5 | |||
f969d5ed28 | |||
87612df54b | |||
6c1d6c3222 | |||
ec6f3e07c5 | |||
72b276bd8f | |||
c52b3c6126 | |||
9b91789193 | |||
d1dfefc897 | |||
ddb1c83695 |
@ -32,17 +32,32 @@
|
||||
ifeq ($(strip $(BOOTLOADER)), atmel-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_ATMEL_DFU
|
||||
OPT_DEFS += -DBOOTLOADER_DFU
|
||||
BOOTLOADER_SIZE = 4096
|
||||
ifeq ($(strip $(MCU)), atmega32u4)
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
ifeq ($(strip $(MCU)), at90usb1286)
|
||||
BOOTLOADER_SIZE = 8192
|
||||
endif
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), lufa-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_LUFA_DFU
|
||||
OPT_DEFS += -DBOOTLOADER_DFU
|
||||
BOOTLOADER_SIZE = 4096
|
||||
ifeq ($(strip $(MCU)), atmega32u4)
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
ifeq ($(strip $(MCU)), at90usb1286)
|
||||
BOOTLOADER_SIZE = 8192
|
||||
endif
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_QMK_DFU
|
||||
OPT_DEFS += -DBOOTLOADER_DFU
|
||||
BOOTLOADER_SIZE = 4096
|
||||
ifeq ($(strip $(MCU)), atmega32u4)
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
ifeq ($(strip $(MCU)), at90usb1286)
|
||||
BOOTLOADER_SIZE = 8192
|
||||
endif
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), halfkay)
|
||||
OPT_DEFS += -DBOOTLOADER_HALFKAY
|
||||
@ -59,4 +74,4 @@ endif
|
||||
|
||||
ifdef BOOTLOADER_SIZE
|
||||
OPT_DEFS += -DBOOTLOADER_SIZE=$(strip $(BOOTLOADER_SIZE))
|
||||
endif
|
||||
endif
|
||||
|
@ -114,6 +114,15 @@ ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
|
||||
OPT_DEFS += -DRGB_MATRIX_ENABLE
|
||||
SRC += is31fl3731.c
|
||||
SRC += TWIlib.c
|
||||
SRC += $(QUANTUM_DIR)/color.c
|
||||
SRC += $(QUANTUM_DIR)/rgb_matrix.c
|
||||
CIE1931_CURVE = yes
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
|
||||
OPT_DEFS += -DTAP_DANCE_ENABLE
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c
|
||||
|
0
docs/.nojekyll
Normal file
0
docs/.nojekyll
Normal file
@ -1,18 +1,25 @@
|
||||
# Quantum Mechanical Keyboard Firmware
|
||||
|
||||
## What is QMK Firmware? {#what-is-qmk-firmware}
|
||||
[](https://github.com/qmk/qmk_firmware/tags)
|
||||
[](https://travis-ci.org/qmk/qmk_firmware)
|
||||
[](https://discord.gg/Uq7gcHh)
|
||||
[](https://docs.qmk.fm)
|
||||
[](https://github.com/qmk/qmk_firmware/pulse/monthly)
|
||||
[](https://github.com/qmk/qmk_firmware/)
|
||||
|
||||
## What is QMK Firmware?
|
||||
|
||||
QMK (*Quantum Mechanical Keyboard*) is an open source community that maintains QMK Firmware, QMK Flasher, qmk.fm, and these docs. QMK Firmware is a keyboard firmware based on the [tmk\_keyboard](http://github.com/tmk/tmk_keyboard) with some useful features for Atmel AVR controllers, and more specifically, the [OLKB product line](http://olkb.com), the [ErgoDox EZ](http://www.ergodox-ez.com) keyboard, and the [Clueboard product line](http://clueboard.co/). It has also been ported to ARM chips using ChibiOS. You can use it to power your own hand-wired or custom keyboard PCB.
|
||||
|
||||
## How to Get It {#how-to-get-it}
|
||||
## How to Get It
|
||||
|
||||
If you plan on contributing a keymap, keyboard, or features to QMK, the easiest thing to do is [fork the repo through Github](https://github.com/qmk/qmk_firmware#fork-destination-box), and clone your repo locally to make your changes, push them, then open a [Pull Request](https://github.com/qmk/qmk_firmware/pulls) from your fork.
|
||||
|
||||
Otherwise, you can either download it directly ([zip](https://github.com/qmk/qmk_firmware/zipball/master), [tar](https://github.com/qmk/qmk_firmware/tarball/master)), or clone it via git (`git@github.com:qmk/qmk_firmware.git`), or https (`https://github.com/qmk/qmk_firmware.git`).
|
||||
|
||||
## How to Compile {#how-to-compile}
|
||||
## How to Compile
|
||||
|
||||
Before you are able to compile, you'll need to [install an environment](getting_started_build_tools.md) for AVR or/and ARM development. Once that is complete, you'll use the `make` command to build a keyboard and keymap with the following notation:
|
||||
Before you are able to compile, you'll need to [install an environment](01_Getting_Started/01_Install_Build_Tools.md) for AVR or/and ARM development. Once that is complete, you'll use the `make` command to build a keyboard and keymap with the following notation:
|
||||
|
||||
make planck/rev4:default
|
||||
|
||||
@ -20,6 +27,6 @@ This would build the `rev4` revision of the `planck` with the `default` keymap.
|
||||
|
||||
make preonic:default
|
||||
|
||||
## How to Customize {#how-to-customize}
|
||||
## How to Customize
|
||||
|
||||
QMK has lots of [features](features.md) to explore, and a good deal of [reference documentation](http://docs.qmk.fm) to dig through. Most features are taken advantage of by modifying your [keymap](keymap.md), and changing the [keycodes](keycodes.md).
|
||||
QMK has lots of [features](05_Features/index.md) to explore, and a good deal of [reference documentation](http://docs.qmk.fm) to dig through. Most features are taken advantage of by modifying your [keymap](07_Reference/Keymap_Overview.md), and changing the [keycodes](06_Keycodes/index.md).
|
||||
|
99
docs/_sidebar.md
Normal file
99
docs/_sidebar.md
Normal file
@ -0,0 +1,99 @@
|
||||
* [Getting Started](README.md)
|
||||
* [QMK Introduction](getting_started_introduction.md)
|
||||
* [Install Build Tools](getting_started_build_tools.md)
|
||||
* Alternative: [Vagrant Guide](getting_started_vagrant.md)
|
||||
* [Build/Compile Instructions](getting_started_make_guide.md)
|
||||
* [Flashing Firmware](flashing.md)
|
||||
* [Contributing to QMK](contributing.md)
|
||||
* [How to Use Github](getting_started_github.md)
|
||||
* [Getting Help](getting_started_getting_help.md)
|
||||
|
||||
* [Complete Newbs Guide](newbs.md)
|
||||
* [Getting Started](newbs_getting_started.md)
|
||||
* [Building Your First Firmware](newbs_building_firmware.md)
|
||||
* [Flashing Firmware](newbs_flashing.md)
|
||||
* [Testing and Debugging](newbs_testing_debugging.md)
|
||||
|
||||
* [FAQ](faq.md)
|
||||
* [General FAQ](faq_general.md)
|
||||
* [Build/Compile QMK](faq_build.md)
|
||||
* [Debugging/Troubleshooting QMK](faq_debug.md)
|
||||
* [Keymap](faq_keymap.md)
|
||||
|
||||
* [Hardware](hardware.md)
|
||||
* [Keyboard Guidelines](hardware_keyboard_guidelines.md)
|
||||
* [AVR Processors](hardware_avr.md)
|
||||
* ARM Processors (TBD)
|
||||
* [Drivers](hardware_drivers.md)
|
||||
|
||||
* [Features](features.md)
|
||||
* [Advanced Keycodes](feature_advanced_keycodes.md)
|
||||
* [Audio](feature_audio.md)
|
||||
* [Auto Shift](feature_auto_shift.md)
|
||||
* [Backlight](feature_backlight.md)
|
||||
* [Bootmagic](feature_bootmagic.md)
|
||||
* [Command](feature_command.md)
|
||||
* [Dynamic Macros](feature_dynamic_macros.md)
|
||||
* [Grave Escape](feature_grave_esc.md)
|
||||
* [Key Lock](feature_key_lock.md)
|
||||
* [Layouts](feature_layouts.md)
|
||||
* [Leader Key](feature_leader_key.md)
|
||||
* [Macros](feature_macros.md)
|
||||
* [Mouse Keys](feature_mouse_keys.md)
|
||||
* [Pointing Device](feature_pointing_device.md)
|
||||
* [PS/2 Mouse](feature_ps2_mouse.md)
|
||||
* [RGB Lighting](feature_rgblight.md)
|
||||
* [Space Cadet Shift](feature_space_cadet.md)
|
||||
* [Space Cadet Shift Enter](feature_space_shift_cadet.md)
|
||||
* [Stenography](feature_stenography.md)
|
||||
* [Swap Hands](feature_swap_hands.md)
|
||||
* [Tap Dance](feature_tap_dance.md)
|
||||
* [Terminal](feature_terminal.md)
|
||||
* [Thermal Printer](feature_thermal_printer.md)
|
||||
* [Unicode](feature_unicode.md)
|
||||
* [Userspace](feature_userspace.md)
|
||||
|
||||
* [Keycodes](keycodes.md)
|
||||
* [Backlight](feature_backlight.md#backlight-keycodes)
|
||||
* [Basic](keycodes_basic.md)
|
||||
* [Bluetooth](feature_bluetooth.md#bluetooth-keycodes)
|
||||
* [Bootmagic](feature_bootmagic.md#bootmagic-keycodes)
|
||||
* [Layer Switching](feature_advanced_keycodes.md#switching-and-toggling-layers)
|
||||
* [Mod+Key](feature_advanced_keycodes.md#modifier-keys)
|
||||
* [Mod Tap](feature_advanced_keycodes.md#mod-tap)
|
||||
* [One Shot Keys](feature_advanced_keycodes.md#one-shot-keys)
|
||||
* [Quantum](quantum_keycodes.md)
|
||||
* [RGB Light](feature_rgblight.md#rgblight-keycodes)
|
||||
* [Shifted Keys](feature_advanced_keycodes.md#shifted-keycodes)
|
||||
* [Stenography](feature_stenography.md#keycode-reference)
|
||||
* [Thermal Printer](feature_thermal_printer.md#thermal-printer-keycodes)
|
||||
* [US ANSI Shifted Keys](keycodes_us_ansi_shifted.md)
|
||||
|
||||
* Reference
|
||||
* [Config Options](config_options.md)
|
||||
* [Customizing Functionality](custom_quantum_functions.md)
|
||||
* [Documentation Best Practices](documentation_best_practices.md)
|
||||
* [Documentation Templates](documentation_templates.md)
|
||||
* [Glossary](reference_glossary.md)
|
||||
* [Keymap Overview](keymap.md)
|
||||
* [Unit Testing](unit_testing.md)
|
||||
|
||||
* For Makers and Modders
|
||||
* [Hand Wiring Guide](hand_wire.md)
|
||||
* [ISP Flashing Guide](isp_flashing_guide.md)
|
||||
|
||||
* For a Deeper Understanding
|
||||
* [How Keyboards Work](how_keyboards_work.md)
|
||||
* [Understanding QMK](understanding_qmk.md)
|
||||
|
||||
* Other Topics
|
||||
* [Using Eclipse with QMK](eclipse.md)
|
||||
|
||||
* QMK Internals (In Progress)
|
||||
* [Defines](internals_defines.md)
|
||||
* [Input Callback Reg](internals_input_callback_reg.md)
|
||||
* [Midi Device](internals_midi_device.md)
|
||||
* [Midi Device Setup Process](internals_midi_device_setup_process.md)
|
||||
* [Midi Util](internals_midi_util.md)
|
||||
* [Send Functions](internals_send_functions.md)
|
||||
* [Sysex Tools](internals_sysex_tools.md)
|
@ -89,6 +89,8 @@ This is a C header file that is one of the first things included, and will persi
|
||||
* tries to keep switch state consistent with keyboard LED state
|
||||
* `#define IS_COMMAND() ( keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) )`
|
||||
* key combination that allows the use of magic commands (useful for debugging)
|
||||
* `#define USB_MAX_POWER_CONSUMPTION`
|
||||
* sets the maximum power (in mA) over USB for the device (default: 500)
|
||||
|
||||
## Features That Can Be Disabled
|
||||
|
||||
|
@ -22,60 +22,27 @@ Your page should generally have multiple "H1" headings. Only H1 and H2 headings
|
||||
|
||||
You can have styled hint blocks drawn around text to draw attention to it.
|
||||
|
||||
```
|
||||
{% hint style='info' %}
|
||||
This uses `hint style='info'`
|
||||
{% endhint %}
|
||||
```
|
||||
|
||||
### Examples:
|
||||
|
||||
{% hint style='info' %}
|
||||
This uses `hint style='info'`
|
||||
{% endhint %}
|
||||
|
||||
{% hint style='tip' %}
|
||||
This uses `hint style='tip'`
|
||||
{% endhint %}
|
||||
|
||||
{% hint style='danger' %}
|
||||
This uses `hint style='danger'`
|
||||
{% endhint %}
|
||||
|
||||
{% hint style='working' %}
|
||||
This uses `hint style='working'`
|
||||
{% endhint %}
|
||||
|
||||
# Styled Terminal Blocks
|
||||
|
||||
You can present styled terminal blocks by including special tokens inside your text block.
|
||||
### Important
|
||||
|
||||
```
|
||||
\`\`\`
|
||||
**[terminal]
|
||||
**[prompt foo@joe]**[path ~]**[delimiter $ ]**[command ./myscript]
|
||||
Normal output line. Nothing special here...
|
||||
But...
|
||||
You can add some colors. What about a warning message?
|
||||
**[warning [WARNING] The color depends on the theme. Could look normal too]
|
||||
What about an error message?
|
||||
**[error [ERROR] This is not the error you are looking for]
|
||||
\`\`\`
|
||||
!> This is important
|
||||
```
|
||||
|
||||
### Example
|
||||
Renders as:
|
||||
|
||||
!> This is important
|
||||
|
||||
### General Tips
|
||||
|
||||
```
|
||||
**[terminal]
|
||||
**[prompt foo@joe]**[path ~]**[delimiter $ ]**[command ./myscript]
|
||||
Normal output line. Nothing special here...
|
||||
But...
|
||||
You can add some colors. What about a warning message?
|
||||
**[warning [WARNING] The color depends on the theme. Could look normal too]
|
||||
What about an error message?
|
||||
**[error [ERROR] This is not the error you are looking for]
|
||||
?> This is a helpful tip.
|
||||
```
|
||||
|
||||
Renders as:
|
||||
|
||||
?> This is a helpful tip.
|
||||
|
||||
|
||||
# Documenting Features
|
||||
|
||||
If you create a new feature for QMK, create a documentation page for it. It doesn't have to be very long, a few sentences describing your feature and a table listing any relevant keycodes is enough. Here is a basic template:
|
||||
@ -94,4 +61,4 @@ This page describes my cool feature. You can use my cool feature to make coffee
|
||||
|KC_SUGAR||Order Sugar|
|
||||
```
|
||||
|
||||
Place your documentation into `docs/feature_<my_cool_feature>.md`, and add that file to the appropriate place in `docs/_summary.md`. If you have added any keycodes be sure to add them to `docs/keycodes.md` with a link back to your feature page.
|
||||
Place your documentation into `docs/feature_<my_cool_feature>.md`, and add that file to the appropriate place in `docs/_sidebar.md`. If you have added any keycodes be sure to add them to `docs/keycodes.md` with a link back to your feature page.
|
||||
|
@ -131,11 +131,9 @@ We've added shortcuts to make common modifier/tap (mod-tap) mappings more compac
|
||||
* `LCAG_T(kc)` - is CtrlAltGui when held and *kc* when tapped
|
||||
* `MEH_T(kc)` - is like Hyper, but not as cool -- does not include the Cmd/Win key, so just sends Alt+Ctrl+Shift.
|
||||
|
||||
{% hint style='info' %}
|
||||
Due to the way that keycodes are structured, any modifiers specified as part of `kc`, such as `LCTL()` or `KC_LPRN`, will only activate when held instead of tapped.
|
||||
?> Due to the way that keycodes are structured, any modifiers specified as part of `kc`, such as `LCTL()` or `KC_LPRN`, will only activate when held instead of tapped.
|
||||
|
||||
Additionally, if there is at least one right modifier, any other modifiers will turn into their right equivalents, so it is not possible to "mix and match" the two.
|
||||
{% endhint %}
|
||||
?> Additionally, if there is at least one right modifier, any other modifiers will turn into their right equivalents, so it is not possible to "mix and match" the two.
|
||||
|
||||
# One Shot Keys
|
||||
|
||||
|
@ -89,6 +89,20 @@ By default, `MUSIC_MASK` is set to `keycode < 0xFF` which means keycodes less th
|
||||
|
||||
Which will capture all keycodes - be careful, this will get you stuck in music mode until you restart your keyboard!
|
||||
|
||||
For a more advanced way to control which keycodes should still be processed, you can use `music_mask_kb(keycode)` in `<keyboard>.c` and `music_mask_user(keycode)` in your `keymap.c`:
|
||||
|
||||
bool music_mask_user(uint16_t keycode) {
|
||||
switch (keycode) {
|
||||
case RAISE:
|
||||
case LOWER:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Things that return false are not part of the mask, and are always processed.
|
||||
|
||||
The pitch standard (`PITCH_STANDARD_A`) is 440.0f by default - to change this, add something like this to your `config.h`:
|
||||
|
||||
#define PITCH_STANDARD_A 432.0f
|
||||
|
@ -88,10 +88,7 @@ occasion. This is simply due to habit and holding some keys a little longer
|
||||
than others. Once you find this value, work on tapping your problem keys a little
|
||||
quicker than normal and you will be set.
|
||||
|
||||
{% hint style='info' %}
|
||||
Auto Shift has three special keys that can help you get this value right very
|
||||
quick. See "Auto Shift Setup" for more details!
|
||||
{% endhint %}
|
||||
?> Auto Shift has three special keys that can help you get this value right very quick. See "Auto Shift Setup" for more details!
|
||||
|
||||
### NO_AUTO_SHIFT_SPECIAL (simple define)
|
||||
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
Macros allow you to send multiple keystrokes when pressing just one key. QMK has a number of ways to define and use macros. These can do anything you want: type common phrases for you, copypasta, repetitive game movements, or even help you code.
|
||||
|
||||
{% hint style='danger' %}
|
||||
**Security Note**: While it is possible to use macros to send passwords, credit card numbers, and other sensitive information it is a supremely bad idea to do so. Anyone who gets a hold of your keyboard will be able to access that information by opening a text editor.
|
||||
{% endhint %}
|
||||
!> **Security Note**: While it is possible to use macros to send passwords, credit card numbers, and other sensitive information it is a supremely bad idea to do so. Anyone who gets a hold of your keyboard will be able to access that information by opening a text editor.
|
||||
|
||||
## The New Way: `SEND_STRING()` & `process_record_user`
|
||||
|
||||
@ -132,9 +130,7 @@ SEND_STRING(".."SS_TAP(X_END));
|
||||
|
||||
## The Old Way: `MACRO()` & `action_get_macro`
|
||||
|
||||
{% hint style='info' %}
|
||||
This is inherited from TMK, and hasn't been updated - it's recommend that you use `SEND_STRING` and `process_record_user` instead.
|
||||
{% endhint %}
|
||||
?> This is inherited from TMK, and hasn't been updated - it's recommend that you use `SEND_STRING` and `process_record_user` instead.
|
||||
|
||||
By default QMK assumes you don't have any macros. To define your macros you create an `action_get_macro()` function. For example:
|
||||
|
||||
|
141
docs/feature_rgb_matrix.md
Normal file
141
docs/feature_rgb_matrix.md
Normal file
@ -0,0 +1,141 @@
|
||||
# RGB Matrix Lighting
|
||||
|
||||
There is basic support for addressable RGB matrix lighting with the I2C IS31FL3731 RGB controller. To enable it, add this to your `rules.mk`:
|
||||
|
||||
RGB_MATRIX_ENABLE = yes
|
||||
|
||||
Configure the hardware via your `config.h`:
|
||||
|
||||
// This is a 7-bit address, that gets left-shifted and bit 0
|
||||
// set to 0 for write, 1 for read (as per I2C protocol)
|
||||
// The address will vary depending on your wiring:
|
||||
// 0b1110100 AD <-> GND
|
||||
// 0b1110111 AD <-> VCC
|
||||
// 0b1110101 AD <-> SCL
|
||||
// 0b1110110 AD <-> SDA
|
||||
#define DRIVER_ADDR_1 0b1110100
|
||||
#define DRIVER_ADDR_2 0b1110110
|
||||
|
||||
#define DRIVER_COUNT 2
|
||||
#define DRIVER_1_LED_TOTAL 25
|
||||
#define DRIVER_2_LED_TOTAL 24
|
||||
#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL
|
||||
|
||||
Currently only 2 drivers are supported, but it would be trivial to support all 4 combinations.
|
||||
|
||||
Define these arrays listing all the LEDs in your `<keyboard>.c`:
|
||||
|
||||
const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
|
||||
/* Refer to IS31 manual for these locations
|
||||
* driver
|
||||
* | R location
|
||||
* | | G location
|
||||
* | | | B location
|
||||
* | | | | */
|
||||
{0, C1_3, C2_3, C3_3},
|
||||
....
|
||||
}
|
||||
|
||||
Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](http://www.issi.com/WW/pdf/31FL3731.pdf). The `driver` is the index of the driver you defined in your `config.h` (`0` or `1` right now).
|
||||
|
||||
const rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
|
||||
/* {row | col << 4}
|
||||
* | {x=0..224, y=0..64}
|
||||
* | | modifier
|
||||
* | | | */
|
||||
{{0|(0<<4)}, {20.36*0, 21.33*0}, 1},
|
||||
{{0|(1<<4)}, {20.36*1, 21.33*0}, 1},
|
||||
....
|
||||
}
|
||||
|
||||
The format for the matrix position used in this array is `{row | (col << 4)}`. The `x` is between (inclusive) 0-224, and `y` is between (inclusive) 0-64. The easiest way to calculate these positions is:
|
||||
|
||||
x = 224 / ( NUMBER_OF_ROWS - 1 ) * ROW_POSITION
|
||||
y = 64 / (NUMBER_OF_COLS - 1 ) * COL_POSITION
|
||||
|
||||
Where all variables are decimels/floats.
|
||||
|
||||
`modifier` is a boolean, whether or not a certain key is considered a modifier (used in some effects).
|
||||
|
||||
## Keycodes
|
||||
|
||||
All RGB keycodes are currently shared with the RGBLIGHT system:
|
||||
|
||||
* `RGB_TOG` - toggle
|
||||
* `RGB_MOD` - cycle through modes
|
||||
* `RGB_HUI` - increase hue
|
||||
* `RGB_HUD` - decrease hue
|
||||
* `RGB_SAI` - increase saturation
|
||||
* `RGB_SAD` - decrease saturation
|
||||
* `RGB_VAI` - increase value
|
||||
* `RGB_VAD` - decrease value
|
||||
|
||||
|
||||
* `RGB_MODE_*` keycodes will generally work, but are not currently mapped to the correct effects for the RGB Matrix system
|
||||
|
||||
## RGB Matrix Effects
|
||||
|
||||
These are the effects that are currently available:
|
||||
|
||||
enum rgb_matrix_effects {
|
||||
RGB_MATRIX_SOLID_COLOR = 1,
|
||||
RGB_MATRIX_SOLID_REACTIVE,
|
||||
RGB_MATRIX_ALPHAS_MODS,
|
||||
RGB_MATRIX_DUAL_BEACON,
|
||||
RGB_MATRIX_GRADIENT_UP_DOWN,
|
||||
RGB_MATRIX_RAINDROPS,
|
||||
RGB_MATRIX_CYCLE_ALL,
|
||||
RGB_MATRIX_CYCLE_LEFT_RIGHT,
|
||||
RGB_MATRIX_CYCLE_UP_DOWN,
|
||||
RGB_MATRIX_RAINBOW_BEACON,
|
||||
RGB_MATRIX_RAINBOW_PINWHEELS,
|
||||
RGB_MATRIX_RAINBOW_MOVING_CHEVRON,
|
||||
RGB_MATRIX_JELLYBEAN_RAINDROPS,
|
||||
#ifdef RGB_MATRIX_KEYPRESSES
|
||||
RGB_MATRIX_SPLASH,
|
||||
RGB_MATRIX_MULTISPLASH,
|
||||
RGB_MATRIX_SOLID_SPLASH,
|
||||
RGB_MATRIX_SOLID_MULTISPLASH,
|
||||
#endif
|
||||
RGB_MATRIX_EFFECT_MAX
|
||||
};
|
||||
|
||||
## Custom layer effects
|
||||
|
||||
Custom layer effects can be done by defining this in your `<keyboard>.c`:
|
||||
|
||||
void rgb_matrix_indicators_kb(void) {
|
||||
// rgb_matrix_set_color(index, red, green, blue);
|
||||
}
|
||||
|
||||
A similar function works in the keymap as `rgb_matrix_indicators_user`.
|
||||
|
||||
## Additional `config.h` Options
|
||||
|
||||
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses (will slow down matrix scan by a lot)
|
||||
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (not recommened)
|
||||
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
|
||||
#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
|
||||
#define RGB_MATRIX_SKIP_FRAMES 1 // number of frames to skip when displaying animations (0 is full effect)
|
||||
|
||||
## EEPROM storage
|
||||
|
||||
The EEPROM for it is currently shared with the RGBLIGHT system (it's generally assumed only one RGB would be used at a time), but could be configured to use its own 32bit address with:
|
||||
|
||||
#define EECONFIG_RGB_MATRIX (uint32_t *)16
|
||||
|
||||
Where `16` is an unused index from `eeconfig.h`.
|
||||
|
||||
## Suspended state
|
||||
|
||||
To use the suspend feature, add this to your `<keyboard>.c`:
|
||||
|
||||
void suspend_power_down_kb(void)
|
||||
{
|
||||
rgb_matrix_set_suspend_state(true);
|
||||
}
|
||||
|
||||
void suspend_wakeup_init_kb(void)
|
||||
{
|
||||
rgb_matrix_set_suspend_state(false);
|
||||
}
|
@ -179,42 +179,124 @@ Below is a specific example:
|
||||
* Double Tap = Send `Escape`
|
||||
* Double Tap and Hold = Send `Alt`
|
||||
|
||||
The following example can be easily expanded to more than 4 quite easily:
|
||||
## Setup
|
||||
|
||||
You will need a few things that can be used for 'Quad Function Tap-Dance'. The suggested setup is to create a user directory for yourself. This directory will contain rules.mk `<your_name>.c` and `<your_name>.h`. This directory should be called `<your_name>`, and located in the top level `users` directory. There should already be a few examples to look at there.
|
||||
|
||||
### In `/qmk_firmware/users/<your_name>/rules.mk`
|
||||
|
||||
Put the following:
|
||||
```c
|
||||
//**************** Definitions needed for quad function to work *********************//
|
||||
//Enums used to clearly convey the state of the tap dance
|
||||
TAP_DANCE_ENABLE = yes
|
||||
SRC += your_name.c
|
||||
```
|
||||
|
||||
Pretty simple. It is a nice way to keep some rules common on all your keymaps.
|
||||
|
||||
|
||||
### In `/qmk_firmware/users/<your_name>/<you_name>.h`
|
||||
|
||||
You will need a few things in this file:
|
||||
|
||||
```c
|
||||
#ifndef YOUR_NAME
|
||||
#define YOUR_NAME
|
||||
|
||||
#include "quantum.h"
|
||||
#include "process_keycode/process_tap_dance.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
bool is_press_action;
|
||||
int state;
|
||||
} xtap;
|
||||
|
||||
enum {
|
||||
SINGLE_TAP = 1,
|
||||
SINGLE_HOLD = 2,
|
||||
DOUBLE_TAP = 3,
|
||||
DOUBLE_HOLD = 4,
|
||||
DOUBLE_SINGLE_TAP = 5 //send SINGLE_TAP twice - NOT DOUBLE_TAP
|
||||
// Add more enums here if you want for triple, quadruple, etc.
|
||||
DOUBLE_SINGLE_TAP = 5, //send two single taps
|
||||
TRIPLE_TAP = 6,
|
||||
TRIPLE_HOLD = 7
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool is_press_action;
|
||||
int state;
|
||||
} tap;
|
||||
//Tap dance enums
|
||||
enum {
|
||||
CTL_X = 0,
|
||||
SOME_OTHER_DANCE
|
||||
}
|
||||
|
||||
int cur_dance (qk_tap_dance_state_t *state);
|
||||
|
||||
//for the x tap dance. Put it here so it can be used in any keymap
|
||||
void x_finished (qk_tap_dance_state_t *state, void *user_data);
|
||||
void x_reset (qk_tap_dance_state_t *state, void *user_data);
|
||||
```
|
||||
|
||||
### In `/qmk_firmware/users/<your_name>/<your_name>.c`
|
||||
|
||||
And then in your user's `.c` file you implement the functions above:
|
||||
|
||||
```c
|
||||
#include "gordon.h"
|
||||
#include "quantum.h"
|
||||
#include "action.h"
|
||||
#include "process_keycode/process_tap_dance.h"
|
||||
|
||||
/* Return an integer that corresponds to what kind of tap dance should be executed.
|
||||
*
|
||||
* How to figure out tap dance state: interrupted and pressed.
|
||||
*
|
||||
* Interrupted: If the state of a dance dance is "interrupted", that means that another key has been hit
|
||||
* under the tapping term. This is typically indicitive that you are trying to "tap" the key.
|
||||
*
|
||||
* Pressed: Whether or not the key is still being pressed. If this value is true, that means the tapping term
|
||||
* has ended, but the key is still being pressed down. This generally means the key is being "held".
|
||||
*
|
||||
* One thing that is currenlty not possible with qmk software in regards to tap dance is to mimic the "permissive hold"
|
||||
* feature. In general, advanced tap dances do not work well if they are used with commonly typed letters.
|
||||
* For example "A". Tap dances are best used on non-letter keys that are not hit while typing letters.
|
||||
*
|
||||
* Good places to put an advanced tap dance:
|
||||
* z,q,x,j,k,v,b, any function key, home/end, comma, semi-colon
|
||||
*
|
||||
* Criteria for "good placement" of a tap dance key:
|
||||
* Not a key that is hit frequently in a sentence
|
||||
* Not a key that is used frequently to double tap, for example 'tab' is often double tapped in a terminal, or
|
||||
* in a web form. So 'tab' would be a poor choice for a tap dance.
|
||||
* Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the
|
||||
* letter 'p', the word 'pepper' would be quite frustating to type.
|
||||
*
|
||||
* For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested
|
||||
*
|
||||
*/
|
||||
int cur_dance (qk_tap_dance_state_t *state) {
|
||||
if (state->count == 1) {
|
||||
//If count = 1, and it has been interrupted - it doesn't matter if it is pressed or not: Send SINGLE_TAP
|
||||
if (state->interrupted || state->pressed==0) return SINGLE_TAP;
|
||||
if (state->interrupted || !state->pressed) return SINGLE_TAP;
|
||||
//key has not been interrupted, but they key is still held. Means you want to send a 'HOLD'.
|
||||
else return SINGLE_HOLD;
|
||||
}
|
||||
//If count = 2, and it has been interrupted - assume that user is trying to type the letter associated
|
||||
//with single tap. In example below, that means to send `xx` instead of `Escape`.
|
||||
else if (state->count == 2) {
|
||||
/*
|
||||
* DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap
|
||||
* action when hitting 'pp'. Suggested use case for this return value is when you want to send two
|
||||
* keystrokes of the key, and not the 'double tap' action/macro.
|
||||
*/
|
||||
if (state->interrupted) return DOUBLE_SINGLE_TAP;
|
||||
else if (state->pressed) return DOUBLE_HOLD;
|
||||
else return DOUBLE_TAP;
|
||||
}
|
||||
else return 6; //magic number. At some point this method will expand to work for more presses
|
||||
//Assumes no one is trying to type the same letter three times (at least not quickly).
|
||||
//If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add
|
||||
//an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP'
|
||||
if (state->count == 3) {
|
||||
if (state->interrupted || !state->pressed) return TRIPLE_TAP;
|
||||
else return TRIPLE_HOLD;
|
||||
}
|
||||
else return 8; //magic number. At some point this method will expand to work for more presses
|
||||
}
|
||||
|
||||
//**************** Definitions needed for quad function to work *********************//
|
||||
|
||||
//instanalize an instance of 'tap' for the 'x' tap dance.
|
||||
static tap xtap_state = {
|
||||
.is_press_action = true,
|
||||
@ -245,6 +327,10 @@ void x_reset (qk_tap_dance_state_t *state, void *user_data) {
|
||||
}
|
||||
xtap_state.state = 0;
|
||||
}
|
||||
|
||||
qk_tap_dance_action_t tap_dance_actions[] = {
|
||||
[X_CTL] = ACTION_TAP_DANCE_FN_ADVANCED(NULL,x_finished, x_reset)
|
||||
};
|
||||
```
|
||||
And then simply add this to your list of tap dance functions:
|
||||
`[X_TAP_DANCE] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished, x_reset)`
|
||||
|
||||
And then simply use TD(X_CTL) anywhere in your keymap.
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
Github can be a little tricky to those that aren't familiar with it - this guide will walk through each step of forking, cloning, and submitting a pull request with QMK.
|
||||
|
||||
{% hint style='info' %}
|
||||
This guide assumes you're somewhat comfortable with running things at the command line, and have git installed on your system.
|
||||
{% endhint %}
|
||||
?> This guide assumes you're somewhat comfortable with running things at the command line, and have git installed on your system.
|
||||
|
||||
Start on the [QMK Github page](https://github.com/qmk/qmk_firmware), and you'll see a button in the upper right that says "Fork":
|
||||
|
||||
|
@ -66,9 +66,7 @@ Do change the `MANUFACTURER`, `PRODUCT`, and `DESCRIPTION` lines to accurately r
|
||||
#define DESCRIPTION A custom keyboard
|
||||
```
|
||||
|
||||
{% hint style='info' %}
|
||||
Note: On Windows and macOS the `MANUFACTURER`, `PRODUCT`, and `DESCRIPTION` fields will be displayed in the list of USB devices. On Linux these values will not be visible in `lsusb`, since Linux takes that information from the list published by the USB-IF.
|
||||
{% endhint %}
|
||||
?> Note: On Windows and macOS the `MANUFACTURER`, `PRODUCT`, and `DESCRIPTION` fields will be displayed in the list of USB devices. On Linux these values will not be visible in `lsusb`, since Linux takes that information from the list published by the USB-IF.
|
||||
|
||||
### Keyboard Matrix Configuration
|
||||
|
||||
|
45
docs/index.html
Normal file
45
docs/index.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Document</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="light">
|
||||
<link rel="stylesheet" href="qmk.css" title="dark" disabled>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'QMK Firmware',
|
||||
nameLink: 'https://qmk.fm/',
|
||||
repo: 'qmk/qmk_firmware',
|
||||
loadSidebar: true,
|
||||
auto2top: true,
|
||||
formatUpdated: '{YYYY}/{MM}/{DD} {HH}:{mm}',
|
||||
search: {
|
||||
paths: 'auto',
|
||||
placeholder: 'Search Documentation...',
|
||||
noData: 'We could not find any documents matching your search.',
|
||||
depth: 6
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-c.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-cpp.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-json.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-makefile.min.js"></script>
|
||||
<script>
|
||||
// Register the offline cache worker
|
||||
if (typeof navigator.serviceWorker !== 'undefined') {
|
||||
navigator.serviceWorker.register('sw.js')
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -8,17 +8,15 @@ If you have closed and reopened your terminal window since following the first p
|
||||
|
||||
Start by navigating to the `keymaps` folder for your keyboard.
|
||||
|
||||
{% hint style='info' %}
|
||||
If you are on macOS or Windows there are commands you can use to easily open the keymaps folder.
|
||||
?> If you are on macOS or Windows there are commands you can use to easily open the keymaps folder.
|
||||
|
||||
macOS:
|
||||
?> macOS:
|
||||
|
||||
open keyboards/<keyboard_folder>/keymaps
|
||||
|
||||
Windows:
|
||||
?> Windows:
|
||||
|
||||
start keyboards/<keyboard_folder>/keymaps
|
||||
{% endhint %}
|
||||
|
||||
## Create a Copy Of The `default` Keymap
|
||||
|
||||
@ -32,9 +30,7 @@ Open up your `keymap.c`. Inside this file you'll find the structure that control
|
||||
|
||||
This line indicates the start of the list of Layers. Below that you'll find lines containing either `LAYOUT` or `KEYMAP`, and these lines indicate the start of a layer. Below that line is the list of keys that comprise a that particular layer.
|
||||
|
||||
{% hint style='danger' %}
|
||||
When editing your keymap file be careful not to add or remove any commas. If you do you will prevent your firmware from compiling and it may not be easy to figure out where the extra, or missing, comma is.
|
||||
{% endhint %}
|
||||
!> When editing your keymap file be careful not to add or remove any commas. If you do you will prevent your firmware from compiling and it may not be easy to figure out where the extra, or missing, comma is.
|
||||
|
||||
## Customize The Layout To Your Liking
|
||||
|
||||
@ -44,9 +40,7 @@ How to complete this step is entirely up to you. Make the one change that's been
|
||||
* [Features](features.md)
|
||||
* [FAQ](faq.md)
|
||||
|
||||
{% hint style='info' %}
|
||||
While you get a feel for how keymaps work, keep each change small. Bigger changes make it harder to debug any problems that arise.
|
||||
{% endhint %}
|
||||
?> While you get a feel for how keymaps work, keep each change small. Bigger changes make it harder to debug any problems that arise.
|
||||
|
||||
## Build Your Firmware
|
||||
|
||||
|
@ -12,17 +12,15 @@ However, the QMK Toolbox is only available for Windows and macOS currently. If
|
||||
|
||||
Begin by opening the QMK Toolbox application. You'll want to locate the firmware file in Finder or Explorer. Your keyboard firmware may be in one of two formats- `.hex` or `.bin`. QMK tries to copy the appropriate one for your keyboard into the root `qmk_firmware` directory.
|
||||
|
||||
{% hint style='info' %}
|
||||
If you are on Windows or macOS there are commands you can use to easily open the current firmware folder in Explorer or Finder.
|
||||
?> If you are on Windows or macOS there are commands you can use to easily open the current firmware folder in Explorer or Finder.
|
||||
|
||||
Windows:
|
||||
?> Windows:
|
||||
|
||||
start .
|
||||
|
||||
macOS:
|
||||
?> macOS:
|
||||
|
||||
open .
|
||||
{% endhint %}
|
||||
|
||||
The firmware file always follows this naming format:
|
||||
|
||||
|
@ -14,9 +14,7 @@ Before you can build keymaps you need to install some software and setup your bu
|
||||
|
||||
You'll need a program that can edit and save **plain text** files. If you are on Windows you can make due with Notepad, and on Linux you can use Gedit, both of which are simple but functional text editors. On macOS you can not use TextEdit.app, it will not save plain text files. You will need to install another program such as Sublime Text.
|
||||
|
||||
{% hint style='info' %}
|
||||
Not sure which text editor to use? Laurence Bradford wrote [a great introduction](https://learntocodewith.me/programming/basics/text-editors/) to the subject.
|
||||
{% endhint %}
|
||||
?> Not sure which text editor to use? Laurence Bradford wrote [a great introduction](https://learntocodewith.me/programming/basics/text-editors/) to the subject.
|
||||
|
||||
### QMK Toolbox
|
||||
|
||||
@ -29,12 +27,9 @@ QMK Toolbox is a Windows and macOS program that allows you to both program and d
|
||||
|
||||
We've tried to make QMK as easy to setup as possible. You only have to prepare your Linux or Unix environment and let QMK install the rest.
|
||||
|
||||
{% hint style="info" %}
|
||||
If you haven't worked with the Linux/Unix command line before there are a few basic concepts and commands you should learn. These resources will teach you enough to work with QMK:
|
||||
|
||||
* [Must Know Linux Commands](https://www.guru99.com/must-know-linux-commands.html)
|
||||
* [Some Basic Unix Commands](https://www.tjhsst.edu/~dhyatt/superap/unixcmd.html)
|
||||
{% endhint %}
|
||||
?> If you haven't worked with the Linux/Unix command line before there are a few basic concepts and commands you should learn. These resources will teach you enough to work with QMK:<br>
|
||||
[Must Know Linux Commands](https://www.guru99.com/must-know-linux-commands.html)<br>
|
||||
[Some Basic Unix Commands](https://www.tjhsst.edu/~dhyatt/superap/unixcmd.html)
|
||||
|
||||
### Windows
|
||||
|
||||
@ -63,9 +58,7 @@ Once you have setup your Linux/Unix environment you are ready to download QMK. W
|
||||
git clone https://github.com/qmk/qmk_firmware.git
|
||||
cd qmk_firmware
|
||||
|
||||
{% hint style='info' %}
|
||||
If you already know [how to use GitHub](getting_started_github.md) we recommend you create and clone your own fork instead. If you don't know what that means you can safely ignore this message.
|
||||
{% endhint %}
|
||||
?> If you already know [how to use GitHub](getting_started_github.md) we recommend you create and clone your own fork instead. If you don't know what that means you can safely ignore this message.
|
||||
|
||||
## Setup QMK
|
||||
|
||||
|
862
docs/qmk.css
Normal file
862
docs/qmk.css
Normal file
File diff suppressed because it is too large
Load Diff
83
docs/sw.js
Normal file
83
docs/sw.js
Normal file
@ -0,0 +1,83 @@
|
||||
/* ===========================================================
|
||||
* docsify sw.js
|
||||
* ===========================================================
|
||||
* Copyright 2016 @huxpro
|
||||
* Licensed under Apache 2.0
|
||||
* Register service worker.
|
||||
* ========================================================== */
|
||||
|
||||
const RUNTIME = 'docsify'
|
||||
const HOSTNAME_WHITELIST = [
|
||||
self.location.hostname,
|
||||
'fonts.gstatic.com',
|
||||
'fonts.googleapis.com',
|
||||
'unpkg.com'
|
||||
]
|
||||
|
||||
// The Util Function to hack URLs of intercepted requests
|
||||
const getFixedUrl = (req) => {
|
||||
var now = Date.now()
|
||||
var url = new URL(req.url)
|
||||
|
||||
// 1. fixed http URL
|
||||
// Just keep syncing with location.protocol
|
||||
// fetch(httpURL) belongs to active mixed content.
|
||||
// And fetch(httpRequest) is not supported yet.
|
||||
url.protocol = self.location.protocol
|
||||
|
||||
// 2. add query for caching-busting.
|
||||
// Github Pages served with Cache-Control: max-age=600
|
||||
// max-age on mutable content is error-prone, with SW life of bugs can even extend.
|
||||
// Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
|
||||
// Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
|
||||
if (url.hostname === self.location.hostname) {
|
||||
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
|
||||
}
|
||||
return url.href
|
||||
}
|
||||
|
||||
/**
|
||||
* @Lifecycle Activate
|
||||
* New one activated when old isnt being used.
|
||||
*
|
||||
* waitUntil(): activating ====> activated
|
||||
*/
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(self.clients.claim())
|
||||
})
|
||||
|
||||
/**
|
||||
* @Functional Fetch
|
||||
* All network requests are being intercepted here.
|
||||
*
|
||||
* void respondWith(Promise<Response> r)
|
||||
*/
|
||||
self.addEventListener('fetch', event => {
|
||||
// Skip some of cross-origin requests, like those for Google Analytics.
|
||||
if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
|
||||
// Stale-while-revalidate
|
||||
// similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
|
||||
// Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
|
||||
const cached = caches.match(event.request)
|
||||
const fixedUrl = getFixedUrl(event.request)
|
||||
const fetched = fetch(fixedUrl, { cache: 'no-store' })
|
||||
const fetchedCopy = fetched.then(resp => resp.clone())
|
||||
|
||||
// Call respondWith() with whatever we get first.
|
||||
// If the fetch fails (e.g disconnected), wait for the cache.
|
||||
// If there’s nothing in cache, wait for the fetch.
|
||||
// If neither yields a response, return offline pages.
|
||||
event.respondWith(
|
||||
Promise.race([fetched.catch(_ => cached), cached])
|
||||
.then(resp => resp || fetched)
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
|
||||
// Update the cache with the version we fetched (only for ok status)
|
||||
event.waitUntil(
|
||||
Promise.all([fetchedCopy, caches.open(RUNTIME)])
|
||||
.then(([response, cache]) => response.ok && cache.put(event.request, response))
|
||||
.catch(_ => { /* eat any errors */ })
|
||||
)
|
||||
}
|
||||
})
|
232
drivers/avr/TWIlib.c
Normal file
232
drivers/avr/TWIlib.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* TWIlib.c
|
||||
*
|
||||
* Created: 6/01/2014 10:41:33 PM
|
||||
* Author: Chris Herring
|
||||
* http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include "TWIlib.h"
|
||||
#include "util/delay.h"
|
||||
|
||||
void TWIInit()
|
||||
{
|
||||
TWIInfo.mode = Ready;
|
||||
TWIInfo.errorCode = 0xFF;
|
||||
TWIInfo.repStart = 0;
|
||||
// Set pre-scalers (no pre-scaling)
|
||||
TWSR = 0;
|
||||
// Set bit rate
|
||||
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
|
||||
// Enable TWI and interrupt
|
||||
TWCR = (1 << TWIE) | (1 << TWEN);
|
||||
}
|
||||
|
||||
uint8_t isTWIReady()
|
||||
{
|
||||
if ( (TWIInfo.mode == Ready) | (TWIInfo.mode == RepeatedStartSent) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart)
|
||||
{
|
||||
if (dataLen <= TXMAXBUFLEN)
|
||||
{
|
||||
// Wait until ready
|
||||
while (!isTWIReady()) {_delay_us(1);}
|
||||
// Set repeated start mode
|
||||
TWIInfo.repStart = repStart;
|
||||
// Copy data into the transmit buffer
|
||||
uint8_t *data = (uint8_t *)TXdata;
|
||||
for (int i = 0; i < dataLen; i++)
|
||||
{
|
||||
TWITransmitBuffer[i] = data[i];
|
||||
}
|
||||
// Copy transmit info to global variables
|
||||
TXBuffLen = dataLen;
|
||||
TXBuffIndex = 0;
|
||||
|
||||
// If a repeated start has been sent, then devices are already listening for an address
|
||||
// and another start does not need to be sent.
|
||||
if (TWIInfo.mode == RepeatedStartSent)
|
||||
{
|
||||
TWIInfo.mode = Initializing;
|
||||
TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
|
||||
TWISendTransmit(); // Send the data
|
||||
}
|
||||
else // Otherwise, just send the normal start signal to begin transmission.
|
||||
{
|
||||
TWIInfo.mode = Initializing;
|
||||
TWISendStart();
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1; // return an error if data length is longer than buffer
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart)
|
||||
{
|
||||
// Check if number of bytes to read can fit in the RXbuffer
|
||||
if (bytesToRead < RXMAXBUFLEN)
|
||||
{
|
||||
// Reset buffer index and set RXBuffLen to the number of bytes to read
|
||||
RXBuffIndex = 0;
|
||||
RXBuffLen = bytesToRead;
|
||||
// Create the one value array for the address to be transmitted
|
||||
uint8_t TXdata[1];
|
||||
// Shift the address and AND a 1 into the read write bit (set to write mode)
|
||||
TXdata[0] = (TWIaddr << 1) | 0x01;
|
||||
// Use the TWITransmitData function to initialize the transfer and address the slave
|
||||
TWITransmitData(TXdata, 1, repStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
ISR (TWI_vect)
|
||||
{
|
||||
switch (TWI_STATUS)
|
||||
{
|
||||
// ----\/ ---- MASTER TRANSMITTER OR WRITING ADDRESS ----\/ ---- //
|
||||
case TWI_MT_SLAW_ACK: // SLA+W transmitted and ACK received
|
||||
// Set mode to Master Transmitter
|
||||
TWIInfo.mode = MasterTransmitter;
|
||||
case TWI_START_SENT: // Start condition has been transmitted
|
||||
case TWI_MT_DATA_ACK: // Data byte has been transmitted, ACK received
|
||||
if (TXBuffIndex < TXBuffLen) // If there is more data to send
|
||||
{
|
||||
TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
TWISendTransmit(); // Send the data
|
||||
}
|
||||
// This transmission is complete however do not release bus yet
|
||||
else if (TWIInfo.repStart)
|
||||
{
|
||||
TWIInfo.errorCode = 0xFF;
|
||||
TWISendStart();
|
||||
}
|
||||
// All transmissions are complete, exit
|
||||
else
|
||||
{
|
||||
TWIInfo.mode = Ready;
|
||||
TWIInfo.errorCode = 0xFF;
|
||||
TWISendStop();
|
||||
}
|
||||
break;
|
||||
|
||||
// ----\/ ---- MASTER RECEIVER ----\/ ---- //
|
||||
|
||||
case TWI_MR_SLAR_ACK: // SLA+R has been transmitted, ACK has been received
|
||||
// Switch to Master Receiver mode
|
||||
TWIInfo.mode = MasterReceiver;
|
||||
// If there is more than one byte to be read, receive data byte and return an ACK
|
||||
if (RXBuffIndex < RXBuffLen-1)
|
||||
{
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
TWISendACK();
|
||||
}
|
||||
// Otherwise when a data byte (the only data byte) is received, return NACK
|
||||
else
|
||||
{
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
TWISendNACK();
|
||||
}
|
||||
break;
|
||||
|
||||
case TWI_MR_DATA_ACK: // Data has been received, ACK has been transmitted.
|
||||
|
||||
/// -- HANDLE DATA BYTE --- ///
|
||||
TWIReceiveBuffer[RXBuffIndex++] = TWDR;
|
||||
// If there is more than one byte to be read, receive data byte and return an ACK
|
||||
if (RXBuffIndex < RXBuffLen-1)
|
||||
{
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
TWISendACK();
|
||||
}
|
||||
// Otherwise when a data byte (the only data byte) is received, return NACK
|
||||
else
|
||||
{
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
TWISendNACK();
|
||||
}
|
||||
break;
|
||||
|
||||
case TWI_MR_DATA_NACK: // Data byte has been received, NACK has been transmitted. End of transmission.
|
||||
|
||||
/// -- HANDLE DATA BYTE --- ///
|
||||
TWIReceiveBuffer[RXBuffIndex++] = TWDR;
|
||||
// This transmission is complete however do not release bus yet
|
||||
if (TWIInfo.repStart)
|
||||
{
|
||||
TWIInfo.errorCode = 0xFF;
|
||||
TWISendStart();
|
||||
}
|
||||
// All transmissions are complete, exit
|
||||
else
|
||||
{
|
||||
TWIInfo.mode = Ready;
|
||||
TWIInfo.errorCode = 0xFF;
|
||||
TWISendStop();
|
||||
}
|
||||
break;
|
||||
|
||||
// ----\/ ---- MT and MR common ----\/ ---- //
|
||||
|
||||
case TWI_MR_SLAR_NACK: // SLA+R transmitted, NACK received
|
||||
case TWI_MT_SLAW_NACK: // SLA+W transmitted, NACK received
|
||||
case TWI_MT_DATA_NACK: // Data byte has been transmitted, NACK received
|
||||
case TWI_LOST_ARBIT: // Arbitration has been lost
|
||||
// Return error and send stop and set mode to ready
|
||||
if (TWIInfo.repStart)
|
||||
{
|
||||
TWIInfo.errorCode = TWI_STATUS;
|
||||
TWISendStart();
|
||||
}
|
||||
// All transmissions are complete, exit
|
||||
else
|
||||
{
|
||||
TWIInfo.mode = Ready;
|
||||
TWIInfo.errorCode = TWI_STATUS;
|
||||
TWISendStop();
|
||||
}
|
||||
break;
|
||||
case TWI_REP_START_SENT: // Repeated start has been transmitted
|
||||
// Set the mode but DO NOT clear TWINT as the next data is not yet ready
|
||||
TWIInfo.mode = RepeatedStartSent;
|
||||
break;
|
||||
|
||||
// ----\/ ---- SLAVE RECEIVER ----\/ ---- //
|
||||
|
||||
// TODO IMPLEMENT SLAVE RECEIVER FUNCTIONALITY
|
||||
|
||||
// ----\/ ---- SLAVE TRANSMITTER ----\/ ---- //
|
||||
|
||||
// TODO IMPLEMENT SLAVE TRANSMITTER FUNCTIONALITY
|
||||
|
||||
// ----\/ ---- MISCELLANEOUS STATES ----\/ ---- //
|
||||
case TWI_NO_RELEVANT_INFO: // It is not really possible to get into this ISR on this condition
|
||||
// Rather, it is there to be manually set between operations
|
||||
break;
|
||||
case TWI_ILLEGAL_START_STOP: // Illegal START/STOP, abort and return error
|
||||
TWIInfo.errorCode = TWI_ILLEGAL_START_STOP;
|
||||
TWIInfo.mode = Ready;
|
||||
TWISendStop();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
82
drivers/avr/TWIlib.h
Normal file
82
drivers/avr/TWIlib.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* TWIlib.h
|
||||
*
|
||||
* Created: 6/01/2014 10:38:42 PM
|
||||
* Author: Chris Herring
|
||||
* http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TWILIB_H_
|
||||
#define TWILIB_H_
|
||||
// TWI bit rate (was 100000)
|
||||
#define TWI_FREQ 400000
|
||||
// Get TWI status
|
||||
#define TWI_STATUS (TWSR & 0xF8)
|
||||
// Transmit buffer length
|
||||
#define TXMAXBUFLEN 20
|
||||
// Receive buffer length
|
||||
#define RXMAXBUFLEN 20
|
||||
// Global transmit buffer
|
||||
uint8_t TWITransmitBuffer[TXMAXBUFLEN];
|
||||
// Global receive buffer
|
||||
volatile uint8_t TWIReceiveBuffer[RXMAXBUFLEN];
|
||||
// Buffer indexes
|
||||
volatile int TXBuffIndex; // Index of the transmit buffer. Is volatile, can change at any time.
|
||||
int RXBuffIndex; // Current index in the receive buffer
|
||||
// Buffer lengths
|
||||
int TXBuffLen; // The total length of the transmit buffer
|
||||
int RXBuffLen; // The total number of bytes to read (should be less than RXMAXBUFFLEN)
|
||||
|
||||
typedef enum {
|
||||
Ready,
|
||||
Initializing,
|
||||
RepeatedStartSent,
|
||||
MasterTransmitter,
|
||||
MasterReceiver,
|
||||
SlaceTransmitter,
|
||||
SlaveReciever
|
||||
} TWIMode;
|
||||
|
||||
typedef struct TWIInfoStruct{
|
||||
TWIMode mode;
|
||||
uint8_t errorCode;
|
||||
uint8_t repStart;
|
||||
}TWIInfoStruct;
|
||||
TWIInfoStruct TWIInfo;
|
||||
|
||||
|
||||
// TWI Status Codes
|
||||
#define TWI_START_SENT 0x08 // Start sent
|
||||
#define TWI_REP_START_SENT 0x10 // Repeated Start sent
|
||||
// Master Transmitter Mode
|
||||
#define TWI_MT_SLAW_ACK 0x18 // SLA+W sent and ACK received
|
||||
#define TWI_MT_SLAW_NACK 0x20 // SLA+W sent and NACK received
|
||||
#define TWI_MT_DATA_ACK 0x28 // DATA sent and ACK received
|
||||
#define TWI_MT_DATA_NACK 0x30 // DATA sent and NACK received
|
||||
// Master Receiver Mode
|
||||
#define TWI_MR_SLAR_ACK 0x40 // SLA+R sent, ACK received
|
||||
#define TWI_MR_SLAR_NACK 0x48 // SLA+R sent, NACK received
|
||||
#define TWI_MR_DATA_ACK 0x50 // Data received, ACK returned
|
||||
#define TWI_MR_DATA_NACK 0x58 // Data received, NACK returned
|
||||
|
||||
// Miscellaneous States
|
||||
#define TWI_LOST_ARBIT 0x38 // Arbitration has been lost
|
||||
#define TWI_NO_RELEVANT_INFO 0xF8 // No relevant information available
|
||||
#define TWI_ILLEGAL_START_STOP 0x00 // Illegal START or STOP condition has been detected
|
||||
#define TWI_SUCCESS 0xFF // Successful transfer, this state is impossible from TWSR as bit2 is 0 and read only
|
||||
|
||||
|
||||
#define TWISendStart() (TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)) // Send the START signal, enable interrupts and TWI, clear TWINT flag to resume transfer.
|
||||
#define TWISendStop() (TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)) // Send the STOP signal, enable interrupts and TWI, clear TWINT flag.
|
||||
#define TWISendTransmit() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // Used to resume a transfer, clear TWINT and ensure that TWI and interrupts are enabled.
|
||||
#define TWISendACK() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)|(1<<TWEA)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled and respond with an ACK if the device is addressed as a slave or after it receives a byte.
|
||||
#define TWISendNACK() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled but DO NOT respond with an ACK if the device is addressed as a slave or after it receives a byte.
|
||||
|
||||
// Function declarations
|
||||
uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart);
|
||||
void TWIInit(void);
|
||||
uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart);
|
||||
uint8_t isTWIReady(void);
|
||||
|
||||
#endif // TWICOMMS_H_
|
258
drivers/avr/is31fl3731.c
Normal file
258
drivers/avr/is31fl3731.c
Normal file
@ -0,0 +1,258 @@
|
||||
/* Copyright 2017 Jason Williams
|
||||
* Copyright 2018 Jack Humbert
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "is31fl3731.h"
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <string.h>
|
||||
#include "TWIlib.h"
|
||||
#include "progmem.h"
|
||||
|
||||
// This is a 7-bit address, that gets left-shifted and bit 0
|
||||
// set to 0 for write, 1 for read (as per I2C protocol)
|
||||
// The address will vary depending on your wiring:
|
||||
// 0b1110100 AD <-> GND
|
||||
// 0b1110111 AD <-> VCC
|
||||
// 0b1110101 AD <-> SCL
|
||||
// 0b1110110 AD <-> SDA
|
||||
#define ISSI_ADDR_DEFAULT 0x74
|
||||
|
||||
#define ISSI_REG_CONFIG 0x00
|
||||
#define ISSI_REG_CONFIG_PICTUREMODE 0x00
|
||||
#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08
|
||||
#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18
|
||||
|
||||
#define ISSI_CONF_PICTUREMODE 0x00
|
||||
#define ISSI_CONF_AUTOFRAMEMODE 0x04
|
||||
#define ISSI_CONF_AUDIOMODE 0x08
|
||||
|
||||
#define ISSI_REG_PICTUREFRAME 0x01
|
||||
|
||||
#define ISSI_REG_SHUTDOWN 0x0A
|
||||
#define ISSI_REG_AUDIOSYNC 0x06
|
||||
|
||||
#define ISSI_COMMANDREGISTER 0xFD
|
||||
#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
uint8_t g_twi_transfer_buffer[TXMAXBUFLEN];
|
||||
|
||||
// These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
|
||||
// Storing them like this is optimal for I2C transfers to the registers.
|
||||
// We could optimize this and take out the unused registers from these
|
||||
// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's
|
||||
// probably not worth the extra complexity.
|
||||
uint8_t g_pwm_buffer[DRIVER_COUNT][144];
|
||||
bool g_pwm_buffer_update_required = false;
|
||||
|
||||
uint8_t g_led_control_registers[DRIVER_COUNT][18] = { { 0 }, { 0 } };
|
||||
bool g_led_control_registers_update_required = false;
|
||||
|
||||
// This is the bit pattern in the LED control registers
|
||||
// (for matrix A, add one to register for matrix B)
|
||||
//
|
||||
// reg - b7 b6 b5 b4 b3 b2 b1 b0
|
||||
// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01
|
||||
// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00
|
||||
// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00
|
||||
// 0x06 - - , - , - , - , - ,B02,B01,B00
|
||||
// 0x08 - - , - , - , - , - , - , - , -
|
||||
// 0x0A - B17,B16,B15, - , - , - , - , -
|
||||
// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09
|
||||
// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09
|
||||
// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09
|
||||
|
||||
|
||||
void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data )
|
||||
{
|
||||
g_twi_transfer_buffer[0] = (addr << 1) | 0x00;
|
||||
g_twi_transfer_buffer[1] = reg;
|
||||
g_twi_transfer_buffer[2] = data;
|
||||
|
||||
// Set the error code to have no relevant information
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
// Continuously attempt to transmit data until a successful transmission occurs
|
||||
//while ( TWIInfo.errorCode != 0xFF )
|
||||
//{
|
||||
TWITransmitData( g_twi_transfer_buffer, 3, 0 );
|
||||
//}
|
||||
}
|
||||
|
||||
void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer )
|
||||
{
|
||||
// assumes bank is already selected
|
||||
|
||||
// transmit PWM registers in 9 transfers of 16 bytes
|
||||
// g_twi_transfer_buffer[] is 20 bytes
|
||||
|
||||
// set the I2C address
|
||||
g_twi_transfer_buffer[0] = (addr << 1) | 0x00;
|
||||
|
||||
// iterate over the pwm_buffer contents at 16 byte intervals
|
||||
for ( int i = 0; i < 144; i += 16 )
|
||||
{
|
||||
// set the first register, e.g. 0x24, 0x34, 0x44, etc.
|
||||
g_twi_transfer_buffer[1] = 0x24 + i;
|
||||
// copy the data from i to i+15
|
||||
// device will auto-increment register for data after the first byte
|
||||
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
|
||||
for ( int j = 0; j < 16; j++ )
|
||||
{
|
||||
g_twi_transfer_buffer[2 + j] = pwm_buffer[i + j];
|
||||
}
|
||||
|
||||
// Set the error code to have no relevant information
|
||||
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||
// Continuously attempt to transmit data until a successful transmission occurs
|
||||
while ( TWIInfo.errorCode != 0xFF )
|
||||
{
|
||||
TWITransmitData( g_twi_transfer_buffer, 16 + 2, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IS31FL3731_init( uint8_t addr )
|
||||
{
|
||||
// In order to avoid the LEDs being driven with garbage data
|
||||
// in the LED driver's PWM registers, first enable software shutdown,
|
||||
// then set up the mode and other settings, clear the PWM registers,
|
||||
// then disable software shutdown.
|
||||
|
||||
// select "function register" bank
|
||||
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
|
||||
|
||||
// enable software shutdown
|
||||
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x00 );
|
||||
// this delay was copied from other drivers, might not be needed
|
||||
_delay_ms( 10 );
|
||||
|
||||
// picture mode
|
||||
IS31FL3731_write_register( addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE );
|
||||
// display frame 0
|
||||
IS31FL3731_write_register( addr, ISSI_REG_PICTUREFRAME, 0x00 );
|
||||
// audio sync off
|
||||
IS31FL3731_write_register( addr, ISSI_REG_AUDIOSYNC, 0x00 );
|
||||
|
||||
// select bank 0
|
||||
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
|
||||
|
||||
// turn off all LEDs in the LED control register
|
||||
for ( int i = 0x00; i <= 0x11; i++ )
|
||||
{
|
||||
IS31FL3731_write_register( addr, i, 0x00 );
|
||||
}
|
||||
|
||||
// turn off all LEDs in the blink control register (not really needed)
|
||||
for ( int i = 0x12; i <= 0x23; i++ )
|
||||
{
|
||||
IS31FL3731_write_register( addr, i, 0x00 );
|
||||
}
|
||||
|
||||
// set PWM on all LEDs to 0
|
||||
for ( int i = 0x24; i <= 0xB3; i++ )
|
||||
{
|
||||
IS31FL3731_write_register( addr, i, 0x00 );
|
||||
}
|
||||
|
||||
// select "function register" bank
|
||||
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
|
||||
|
||||
// disable software shutdown
|
||||
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x01 );
|
||||
|
||||
// select bank 0 and leave it selected.
|
||||
// most usage after initialization is just writing PWM buffers in bank 0
|
||||
// as there's not much point in double-buffering
|
||||
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
|
||||
}
|
||||
|
||||
void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue )
|
||||
{
|
||||
if ( index >= 0 && index < DRIVER_LED_TOTAL ) {
|
||||
is31_led led = g_is31_leds[index];
|
||||
|
||||
// Subtract 0x24 to get the second index of g_pwm_buffer
|
||||
g_pwm_buffer[led.driver][led.r - 0x24] = red;
|
||||
g_pwm_buffer[led.driver][led.g - 0x24] = green;
|
||||
g_pwm_buffer[led.driver][led.b - 0x24] = blue;
|
||||
g_pwm_buffer_update_required = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
|
||||
{
|
||||
for ( int i = 0; i < DRIVER_LED_TOTAL; i++ )
|
||||
{
|
||||
IS31FL3731_set_color( i, red, green, blue );
|
||||
}
|
||||
}
|
||||
|
||||
void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue )
|
||||
{
|
||||
is31_led led = g_is31_leds[index];
|
||||
|
||||
uint8_t control_register_r = (led.r - 0x24) / 8;
|
||||
uint8_t control_register_g = (led.g - 0x24) / 8;
|
||||
uint8_t control_register_b = (led.b - 0x24) / 8;
|
||||
uint8_t bit_r = (led.r - 0x24) % 8;
|
||||
uint8_t bit_g = (led.g - 0x24) % 8;
|
||||
uint8_t bit_b = (led.b - 0x24) % 8;
|
||||
|
||||
if ( red ) {
|
||||
g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
|
||||
} else {
|
||||
g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
|
||||
}
|
||||
if ( green ) {
|
||||
g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
|
||||
} else {
|
||||
g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
|
||||
}
|
||||
if ( blue ) {
|
||||
g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
|
||||
} else {
|
||||
g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
|
||||
}
|
||||
|
||||
g_led_control_registers_update_required = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 )
|
||||
{
|
||||
if ( g_pwm_buffer_update_required )
|
||||
{
|
||||
IS31FL3731_write_pwm_buffer( addr1, g_pwm_buffer[0] );
|
||||
IS31FL3731_write_pwm_buffer( addr2, g_pwm_buffer[1] );
|
||||
}
|
||||
g_pwm_buffer_update_required = false;
|
||||
}
|
||||
|
||||
void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 )
|
||||
{
|
||||
if ( g_led_control_registers_update_required )
|
||||
{
|
||||
for ( int i=0; i<18; i++ )
|
||||
{
|
||||
IS31FL3731_write_register(addr1, i, g_led_control_registers[0][i] );
|
||||
IS31FL3731_write_register(addr2, i, g_led_control_registers[1][i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
214
drivers/avr/is31fl3731.h
Normal file
214
drivers/avr/is31fl3731.h
Normal file
@ -0,0 +1,214 @@
|
||||
/* Copyright 2017 Jason Williams
|
||||
* Copyright 2018 Jack Humbert
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IS31FL3731_DRIVER_H
|
||||
#define IS31FL3731_DRIVER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct is31_led {
|
||||
uint8_t driver:2;
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} __attribute__((packed)) is31_led;
|
||||
|
||||
extern const is31_led g_is31_leds[DRIVER_LED_TOTAL];
|
||||
|
||||
void IS31FL3731_init( uint8_t addr );
|
||||
void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data );
|
||||
void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer );
|
||||
|
||||
void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue );
|
||||
void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue );
|
||||
|
||||
void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue );
|
||||
|
||||
// This should not be called from an interrupt
|
||||
// (eg. from a timer interrupt).
|
||||
// Call this while idle (in between matrix scans).
|
||||
// If the buffer is dirty, it will update the driver with the buffer.
|
||||
void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 );
|
||||
void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 );
|
||||
|
||||
#define C1_1 0x24
|
||||
#define C1_2 0x25
|
||||
#define C1_3 0x26
|
||||
#define C1_4 0x27
|
||||
#define C1_5 0x28
|
||||
#define C1_6 0x29
|
||||
#define C1_7 0x2A
|
||||
#define C1_8 0x2B
|
||||
|
||||
#define C1_9 0x2C
|
||||
#define C1_10 0x2D
|
||||
#define C1_11 0x2E
|
||||
#define C1_12 0x2F
|
||||
#define C1_13 0x30
|
||||
#define C1_14 0x31
|
||||
#define C1_15 0x32
|
||||
#define C1_16 0x33
|
||||
|
||||
#define C2_1 0x34
|
||||
#define C2_2 0x35
|
||||
#define C2_3 0x36
|
||||
#define C2_4 0x37
|
||||
#define C2_5 0x38
|
||||
#define C2_6 0x39
|
||||
#define C2_7 0x3A
|
||||
#define C2_8 0x3B
|
||||
|
||||
#define C2_9 0x3C
|
||||
#define C2_10 0x3D
|
||||
#define C2_11 0x3E
|
||||
#define C2_12 0x3F
|
||||
#define C2_13 0x40
|
||||
#define C2_14 0x41
|
||||
#define C2_15 0x42
|
||||
#define C2_16 0x43
|
||||
|
||||
#define C3_1 0x44
|
||||
#define C3_2 0x45
|
||||
#define C3_3 0x46
|
||||
#define C3_4 0x47
|
||||
#define C3_5 0x48
|
||||
#define C3_6 0x49
|
||||
#define C3_7 0x4A
|
||||
#define C3_8 0x4B
|
||||
|
||||
#define C3_9 0x4C
|
||||
#define C3_10 0x4D
|
||||
#define C3_11 0x4E
|
||||
#define C3_12 0x4F
|
||||
#define C3_13 0x50
|
||||
#define C3_14 0x51
|
||||
#define C3_15 0x52
|
||||
#define C3_16 0x53
|
||||
|
||||
#define C4_1 0x54
|
||||
#define C4_2 0x55
|
||||
#define C4_3 0x56
|
||||
#define C4_4 0x57
|
||||
#define C4_5 0x58
|
||||
#define C4_6 0x59
|
||||
#define C4_7 0x5A
|
||||
#define C4_8 0x5B
|
||||
|
||||
#define C4_9 0x5C
|
||||
#define C4_10 0x5D
|
||||
#define C4_11 0x5E
|
||||
#define C4_12 0x5F
|
||||
#define C4_13 0x60
|
||||
#define C4_14 0x61
|
||||
#define C4_15 0x62
|
||||
#define C4_16 0x63
|
||||
|
||||
#define C5_1 0x64
|
||||
#define C5_2 0x65
|
||||
#define C5_3 0x66
|
||||
#define C5_4 0x67
|
||||
#define C5_5 0x68
|
||||
#define C5_6 0x69
|
||||
#define C5_7 0x6A
|
||||
#define C5_8 0x6B
|
||||
|
||||
#define C5_9 0x6C
|
||||
#define C5_10 0x6D
|
||||
#define C5_11 0x6E
|
||||
#define C5_12 0x6F
|
||||
#define C5_13 0x70
|
||||
#define C5_14 0x71
|
||||
#define C5_15 0x72
|
||||
#define C5_16 0x73
|
||||
|
||||
#define C6_1 0x74
|
||||
#define C6_2 0x75
|
||||
#define C6_3 0x76
|
||||
#define C6_4 0x77
|
||||
#define C6_5 0x78
|
||||
#define C6_6 0x79
|
||||
#define C6_7 0x7A
|
||||
#define C6_8 0x7B
|
||||
|
||||
#define C6_9 0x7C
|
||||
#define C6_10 0x7D
|
||||
#define C6_11 0x7E
|
||||
#define C6_12 0x7F
|
||||
#define C6_13 0x80
|
||||
#define C6_14 0x81
|
||||
#define C6_15 0x82
|
||||
#define C6_16 0x83
|
||||
|
||||
#define C7_1 0x84
|
||||
#define C7_2 0x85
|
||||
#define C7_3 0x86
|
||||
#define C7_4 0x87
|
||||
#define C7_5 0x88
|
||||
#define C7_6 0x89
|
||||
#define C7_7 0x8A
|
||||
#define C7_8 0x8B
|
||||
|
||||
#define C7_9 0x8C
|
||||
#define C7_10 0x8D
|
||||
#define C7_11 0x8E
|
||||
#define C7_12 0x8F
|
||||
#define C7_13 0x90
|
||||
#define C7_14 0x91
|
||||
#define C7_15 0x92
|
||||
#define C7_16 0x93
|
||||
|
||||
#define C8_1 0x94
|
||||
#define C8_2 0x95
|
||||
#define C8_3 0x96
|
||||
#define C8_4 0x97
|
||||
#define C8_5 0x98
|
||||
#define C8_6 0x99
|
||||
#define C8_7 0x9A
|
||||
#define C8_8 0x9B
|
||||
|
||||
#define C8_9 0x9C
|
||||
#define C8_10 0x9D
|
||||
#define C8_11 0x9E
|
||||
#define C8_12 0x9F
|
||||
#define C8_13 0xA0
|
||||
#define C8_14 0xA1
|
||||
#define C8_15 0xA2
|
||||
#define C8_16 0xA3
|
||||
|
||||
#define C9_1 0xA4
|
||||
#define C9_2 0xA5
|
||||
#define C9_3 0xA6
|
||||
#define C9_4 0xA7
|
||||
#define C9_5 0xA8
|
||||
#define C9_6 0xA9
|
||||
#define C9_7 0xAA
|
||||
#define C9_8 0xAB
|
||||
|
||||
#define C9_9 0xAC
|
||||
#define C9_10 0xAD
|
||||
#define C9_11 0xAE
|
||||
#define C9_12 0xAF
|
||||
#define C9_13 0xB0
|
||||
#define C9_14 0xB1
|
||||
#define C9_15 0xB2
|
||||
#define C9_16 0xB3
|
||||
|
||||
|
||||
|
||||
#endif // IS31FL3731_DRIVER_H
|
@ -49,7 +49,7 @@
|
||||
#define RGB_DI_PIN E2
|
||||
#ifdef RGB_DI_PIN
|
||||
#define RGBLIGHT_ANIMATIONS
|
||||
#define RGBLED_NUM 20
|
||||
#define RGBLED_NUM 16
|
||||
#define RGBLIGHT_HUE_STEP 8
|
||||
#define RGBLIGHT_SAT_STEP 8
|
||||
#define RGBLIGHT_VAL_STEP 8
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "atom47.h"
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// These are all aliases for the function layers.
|
||||
#define _L0 0
|
||||
@ -9,25 +9,25 @@
|
||||
#define _______ KC_TRNS
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_L0] = KEYMAP_ANSI(
|
||||
[_L0] = LAYOUT_ansi(
|
||||
KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, \
|
||||
KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_ENT, \
|
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, MO(_L1), \
|
||||
KC_LCTL, KC_LGUI, KC_LALT, TG(_L3), KC_SPC, KC_SPC, MO(_L2), KC_RALT, KC_APP, KC_RCTRL), \
|
||||
|
||||
[_L2] = KEYMAP_ANSI(
|
||||
[_L2] = LAYOUT_ansi(
|
||||
_______, KC_VOLD, KC_VOLU, KC_MUTE, RESET, _______, KC_CALC, KC_PGUP, KC_UP, KC_PGDN, KC_PSCR, KC_SLCK, KC_PAUS, \
|
||||
KC_CAPS, KC_MPRV, KC_MPLY, KC_MNXT, _______, _______, KC_HOME, KC_LEFT, KC_DOWN, KC_RIGHT, KC_INS, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, BL_TOGG, BL_DEC, BL_INC, _______, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______), \
|
||||
|
||||
[_L1] = KEYMAP_ANSI(
|
||||
[_L1] = LAYOUT_ansi(
|
||||
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, \
|
||||
KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, \
|
||||
_______, _______, _______, _______, _______, KC_QUOT, KC_SLSH, KC_LBRC, KC_RBRC, KC_BSLS, KC_RSFT, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______), \
|
||||
|
||||
[_L3] = KEYMAP_ANSI(
|
||||
[_L3] = LAYOUT_ansi(
|
||||
_______, _______, _______, KC_7, KC_8, KC_9, _______, _______, _______, _______, _______, _______, _______, \
|
||||
_______, _______, _______, KC_4, KC_5, KC_6, _______, _______, _______, _______, _______, _______, \
|
||||
_______, _______, _______, KC_1, KC_2, KC_3, _______, _______, _______, _______, _______, _______, \
|
@ -1,4 +1,4 @@
|
||||
#include "atom47.h"
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// Each layer gets a name for readability, which is then used in the keymap matrix below.
|
||||
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
|
||||
@ -13,25 +13,25 @@
|
||||
#define _______ KC_TRNS
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_MA] = KEYMAP_ANSI(
|
||||
[_MA] = LAYOUT_ansi(
|
||||
KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, \
|
||||
KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_ENT, \
|
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, MO(_FN1), \
|
||||
KC_LCTL, KC_LGUI, KC_LALT, MO(_PN), KC_SPC, KC_SPC, MO(_FN), KC_RALT, KC_APP, KC_RCTRL), \
|
||||
|
||||
[_FN] = KEYMAP_ANSI(
|
||||
[_FN] = LAYOUT_ansi(
|
||||
_______, KC_VOLD, KC_VOLU, KC_MUTE, RESET, _______, KC_CALC, KC_PGUP, KC_UP, KC_PGDN, KC_PSCR, KC_SLCK, KC_PAUS, \
|
||||
KC_CAPS, KC_MPRV, KC_MPLY, KC_MNXT, _______, _______, KC_HOME, KC_LEFT, KC_DOWN, KC_RIGHT, KC_INS, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, BL_TOGG, BL_DEC, BL_INC, _______, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______), \
|
||||
|
||||
[_FN1] = KEYMAP_ANSI(
|
||||
[_FN1] = LAYOUT_ansi(
|
||||
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, \
|
||||
KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, \
|
||||
_______, _______, _______, _______, _______, KC_QUOT, KC_SLSH, KC_LBRC, KC_RBRC, KC_BSLS, KC_RSFT, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______), \
|
||||
|
||||
[_PN] = KEYMAP_ANSI(
|
||||
[_PN] = LAYOUT_ansi(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||
RGB_TOG, RGB_HUI, RGB_SAI, RGB_VAI, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||
RGB_MOD, RGB_HUD, RGB_SAD, RGB_VAD, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "atom47.h"
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// Each layer gets a name for readability, which is then used in the keymap matrix below.
|
||||
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
|
||||
@ -19,19 +19,19 @@ enum custom_keycodes {
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_MA] = KEYMAP_ANSI(
|
||||
[_MA] = LAYOUT_ansi(
|
||||
KC_GESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, \
|
||||
KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_ENT, \
|
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, \
|
||||
KC_LCTL, KC_LGUI, KC_LALT, MO(_LO), KC_SPC, KC_SPC, MO(_RA), KC_RALT, KC_APP, KC_RCTRL), \
|
||||
|
||||
[_LO] = KEYMAP_ANSI(
|
||||
[_LO] = LAYOUT_ansi(
|
||||
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, \
|
||||
KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, \
|
||||
_______, CTRLZ, CTRLX, CTRLC, CTRLV, _______, _______, KC_QUOT, KC_LBRC, KC_RBRC, KC_BSLS, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, RESET), \
|
||||
|
||||
[_RA] = KEYMAP_ANSI(
|
||||
[_RA] = LAYOUT_ansi(
|
||||
_______, _______, _______, _______, _______, _______, _______, KC_PGUP, KC_UP, KC_PGDN, _______, _______, _______, \
|
||||
KC_CAPS, _______, _______, _______, _______, _______, _______, KC_LEFT, KC_DOWN, KC_RIGHT, _______, _______, \
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, KC_VOLD, KC_VOLU, KC_MPLY, KC_PSCR, \
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user