1 /* Copyright 2019 Jason Williams (Wilba)
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # error "RAW_ENABLE is not enabled"
21 #ifndef DYNAMIC_KEYMAP_ENABLE
22 # error "DYNAMIC_KEYMAP_ENABLE is not enabled"
29 #include "dynamic_keymap.h"
30 #include "tmk_core/common/eeprom.h"
31 #include "version.h" // for QMK_BUILDDATE used in EEPROM magic
33 // Can be called in an overriding via_init_kb() to test if keyboard level code usage of
34 // EEPROM is invalid and use/save defaults.
35 bool via_eeprom_is_valid(void)
37 char *p
= QMK_BUILDDATE
; // e.g. "2019-11-05-11:29:54"
38 uint8_t magic0
= ( ( p
[2] & 0x0F ) << 4 ) | ( p
[3] & 0x0F );
39 uint8_t magic1
= ( ( p
[5] & 0x0F ) << 4 ) | ( p
[6] & 0x0F );
40 uint8_t magic2
= ( ( p
[8] & 0x0F ) << 4 ) | ( p
[9] & 0x0F );
42 return (eeprom_read_byte( (void*)VIA_EEPROM_MAGIC_ADDR
+0 ) == magic0
&&
43 eeprom_read_byte( (void*)VIA_EEPROM_MAGIC_ADDR
+1 ) == magic1
&&
44 eeprom_read_byte( (void*)VIA_EEPROM_MAGIC_ADDR
+2 ) == magic2
);
47 // Sets VIA/keyboard level usage of EEPROM to valid/invalid
48 // Keyboard level code (eg. via_init_kb()) should not call this
49 void via_eeprom_set_valid(bool valid
)
51 char *p
= QMK_BUILDDATE
; // e.g. "2019-11-05-11:29:54"
52 uint8_t magic0
= ( ( p
[2] & 0x0F ) << 4 ) | ( p
[3] & 0x0F );
53 uint8_t magic1
= ( ( p
[5] & 0x0F ) << 4 ) | ( p
[6] & 0x0F );
54 uint8_t magic2
= ( ( p
[8] & 0x0F ) << 4 ) | ( p
[9] & 0x0F );
56 eeprom_update_byte( (void*)VIA_EEPROM_MAGIC_ADDR
+0, valid
? magic0
: 0xFF);
57 eeprom_update_byte( (void*)VIA_EEPROM_MAGIC_ADDR
+1, valid
? magic1
: 0xFF);
58 eeprom_update_byte( (void*)VIA_EEPROM_MAGIC_ADDR
+2, valid
? magic2
: 0xFF);
61 // Flag QMK and VIA/keyboard level EEPROM as invalid.
62 // Used in bootmagic_lite() and VIA command handler.
63 // Keyboard level code should not need to call this.
64 void via_eeprom_reset(void)
66 // Set the VIA specific EEPROM state as invalid.
67 via_eeprom_set_valid(false);
68 // Set the TMK/QMK EEPROM state as invalid.
72 // Override bootmagic_lite() so it can flag EEPROM as invalid
73 // as well as jump to bootloader, thus performing a "factory reset"
74 // of dynamic keymaps and optionally backlight/other settings.
75 void bootmagic_lite(void)
77 // The lite version of TMK's bootmagic based on Wilba.
78 // 100% less potential for accidentally making the
79 // keyboard do stupid things.
81 // We need multiple scans because debouncing can't be turned off.
83 #if defined(DEBOUNCE) && DEBOUNCE > 0
84 wait_ms(DEBOUNCE
* 2);
90 // If the Esc and space bar are held down on power up,
91 // reset the EEPROM valid state and jump to bootloader.
92 // Assumes Esc is at [0,0].
93 // This isn't very generalized, but we need something that doesn't
94 // rely on user's keymaps in firmware or EEPROM.
95 if (matrix_get_row(BOOTMAGIC_LITE_ROW
) & (1 << BOOTMAGIC_LITE_COLUMN
)) {
96 // This is the only difference from the default implementation.
98 // Jump to bootloader.
103 // Override this at the keyboard code level to check
104 // VIA's EEPROM valid state and reset to defaults as needed.
105 // Used by keyboards that store their own state in EEPROM,
106 // for backlight, rotary encoders, etc.
107 // The override should not set via_eeprom_set_valid(true) as
108 // the caller also needs to check the valid state.
109 __attribute__((weak
)) void via_init_kb(void) {
112 // Called by QMK core to initialize dynamic keymaps etc.
115 // Let keyboard level test EEPROM valid state,
116 // but not set it valid, it is done here.
119 // If the EEPROM has the magic, the data is good.
120 // OK to load from EEPROM.
121 if (via_eeprom_is_valid()) {
123 // This resets the layout options
124 via_set_layout_options(0);
125 // This resets the keymaps in EEPROM to what is in flash.
126 dynamic_keymap_reset();
127 // This resets the macros in EEPROM to nothing.
128 dynamic_keymap_macro_reset();
129 // Save the magic number last, in case saving was interrupted
130 via_eeprom_set_valid(true);
134 // This is generalized so the layout options EEPROM usage can be
135 // variable, between 1 and 4 bytes.
136 uint32_t via_get_layout_options(void)
139 // Start at the most significant byte
140 void * source
= (void *)(VIA_EEPROM_LAYOUT_OPTIONS_ADDR
);
141 for ( uint8_t i
= 0; i
< VIA_EEPROM_LAYOUT_OPTIONS_SIZE
; i
++ ) {
143 value
|= eeprom_read_byte(source
);
149 void via_set_layout_options(uint32_t value
)
151 // Start at the least significant byte
152 void * target
= (void *)(VIA_EEPROM_LAYOUT_OPTIONS_ADDR
+VIA_EEPROM_LAYOUT_OPTIONS_SIZE
-1);
153 for ( uint8_t i
= 0; i
< VIA_EEPROM_LAYOUT_OPTIONS_SIZE
; i
++ ) {
154 eeprom_update_byte(target
, value
& 0xFF );
160 // Called by QMK core to process VIA-specific keycodes.
161 bool process_record_via(uint16_t keycode
, keyrecord_t
*record
)
164 if (record
->event
.pressed
) {
165 if ( keycode
>= MACRO00
&& keycode
<= MACRO15
)
167 uint8_t id
= keycode
- MACRO00
;
168 dynamic_keymap_macro_send(id
);
173 // TODO: ideally this would be generalized and refactored into
174 // QMK core as advanced keycodes, until then, the simple case
175 // can be available here to keyboards using VIA
178 if (record
->event
.pressed
) {
180 update_tri_layer(1, 2, 3);
183 update_tri_layer(1, 2, 3);
188 if (record
->event
.pressed
) {
190 update_tri_layer(1, 2, 3);
193 update_tri_layer(1, 2, 3);
201 // Keyboard level code can override this to handle custom messages from VIA.
202 // See raw_hid_receive() implementation.
203 // DO NOT call raw_hid_send() in the overide function.
204 __attribute__((weak
)) void raw_hid_receive_kb(uint8_t *data
, uint8_t length
) {
205 uint8_t *command_id
= &(data
[0]);
206 *command_id
= id_unhandled
;
209 // VIA handles received HID messages first, and will route to
210 // raw_hid_receive_kb() for command IDs that are not handled here.
211 // This gives the keyboard code level the ability to handle the command
214 // raw_hid_send() is called at the end, with the same buffer, which was
215 // possibly modified with returned values.
216 void raw_hid_receive( uint8_t *data
, uint8_t length
)
218 uint8_t *command_id
= &(data
[0]);
219 uint8_t *command_data
= &(data
[1]);
220 switch ( *command_id
)
222 case id_get_protocol_version
:
224 command_data
[0] = VIA_PROTOCOL_VERSION
>> 8;
225 command_data
[1] = VIA_PROTOCOL_VERSION
& 0xFF;
228 case id_get_keyboard_value
:
230 switch ( command_data
[0] )
234 uint32_t value
= timer_read32();
235 command_data
[1] = (value
>> 24 ) & 0xFF;
236 command_data
[2] = (value
>> 16 ) & 0xFF;
237 command_data
[3] = (value
>> 8 ) & 0xFF;
238 command_data
[4] = value
& 0xFF;
241 case id_layout_options
:
243 uint32_t value
= via_get_layout_options();
244 command_data
[1] = (value
>> 24 ) & 0xFF;
245 command_data
[2] = (value
>> 16 ) & 0xFF;
246 command_data
[3] = (value
>> 8 ) & 0xFF;
247 command_data
[4] = value
& 0xFF;
250 case id_switch_matrix_state
:
252 #if ( (MATRIX_COLS/8+1)*MATRIX_ROWS <= 28 )
254 for ( uint8_t row
=0; row
<MATRIX_ROWS
; row
++ ) {
255 matrix_row_t value
= matrix_get_row(row
);
256 #if (MATRIX_COLS > 24)
257 command_data
[i
++] = (value
>> 24 ) & 0xFF;
259 #if (MATRIX_COLS > 16)
260 command_data
[i
++] = (value
>> 16 ) & 0xFF;
262 #if (MATRIX_COLS > 8)
263 command_data
[i
++] = (value
>> 8 ) & 0xFF;
265 command_data
[i
++] = value
& 0xFF;
272 raw_hid_receive_kb(data
,length
);
278 case id_set_keyboard_value
:
280 switch ( command_data
[0] )
282 case id_layout_options
:
284 uint32_t value
= ( (uint32_t)command_data
[1] << 24 ) |
285 ( (uint32_t)command_data
[2] << 16 ) |
286 ( (uint32_t)command_data
[3] << 8 ) |
287 (uint32_t)command_data
[4];
288 via_set_layout_options(value
);
293 raw_hid_receive_kb(data
,length
);
299 case id_dynamic_keymap_get_keycode
:
301 uint16_t keycode
= dynamic_keymap_get_keycode( command_data
[0], command_data
[1], command_data
[2] );
302 command_data
[3] = keycode
>> 8;
303 command_data
[4] = keycode
& 0xFF;
306 case id_dynamic_keymap_set_keycode
:
308 dynamic_keymap_set_keycode( command_data
[0], command_data
[1], command_data
[2], ( command_data
[3] << 8 ) | command_data
[4] );
311 case id_dynamic_keymap_reset
:
313 dynamic_keymap_reset();
316 case id_backlight_config_set_value
:
317 case id_backlight_config_get_value
:
318 case id_backlight_config_save
:
320 raw_hid_receive_kb(data
, length
);
323 case id_dynamic_keymap_macro_get_count
:
325 command_data
[0] = dynamic_keymap_macro_get_count();
328 case id_dynamic_keymap_macro_get_buffer_size
:
330 uint16_t size
= dynamic_keymap_macro_get_buffer_size();
331 command_data
[0] = size
>> 8;
332 command_data
[1] = size
& 0xFF;
335 case id_dynamic_keymap_macro_get_buffer
:
337 uint16_t offset
= ( command_data
[0] << 8 ) | command_data
[1];
338 uint16_t size
= command_data
[2]; // size <= 28
339 dynamic_keymap_macro_get_buffer( offset
, size
, &command_data
[3] );
342 case id_dynamic_keymap_macro_set_buffer
:
344 uint16_t offset
= ( command_data
[0] << 8 ) | command_data
[1];
345 uint16_t size
= command_data
[2]; // size <= 28
346 dynamic_keymap_macro_set_buffer( offset
, size
, &command_data
[3] );
349 case id_dynamic_keymap_macro_reset
:
351 dynamic_keymap_macro_reset();
354 case id_dynamic_keymap_get_layer_count
:
356 command_data
[0] = dynamic_keymap_get_layer_count();
359 case id_dynamic_keymap_get_buffer
:
361 uint16_t offset
= ( command_data
[0] << 8 ) | command_data
[1];
362 uint16_t size
= command_data
[2]; // size <= 28
363 dynamic_keymap_get_buffer( offset
, size
, &command_data
[3] );
366 case id_dynamic_keymap_set_buffer
:
368 uint16_t offset
= ( command_data
[0] << 8 ) | command_data
[1];
369 uint16_t size
= command_data
[2]; // size <= 28
370 dynamic_keymap_set_buffer( offset
, size
, &command_data
[3] );
373 case id_eeprom_reset
:
378 case id_bootloader_jump
:
380 // Need to send data back before the jump
381 // Informs host that the command is handled
382 raw_hid_send( data
, length
);
383 // Give host time to read it
390 // The command ID is not known
391 // Return the unhandled state
392 *command_id
= id_unhandled
;
397 // Return the same buffer, optionally with values changed
398 // (i.e. returning state to the host, or the unhandled state).
399 raw_hid_send( data
, length
);