aboutsummaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/audio.c362
-rw-r--r--quantum/audio.h11
-rw-r--r--quantum/audio/audio.c477
-rw-r--r--quantum/audio/audio.h91
-rw-r--r--quantum/audio/audio_pwm.c643
-rw-r--r--quantum/audio/luts.c382
-rw-r--r--quantum/audio/luts.h15
-rw-r--r--quantum/audio/musical_notes.h217
-rw-r--r--quantum/audio/song_list.h125
-rw-r--r--quantum/audio/voices.c165
-rw-r--r--quantum/audio/voices.h31
-rw-r--r--quantum/audio/wave.h (renamed from quantum/wave.h)0
-rw-r--r--quantum/config_common.h132
-rw-r--r--quantum/dynamic_macro.h231
-rw-r--r--quantum/keycode_config.c74
-rw-r--r--quantum/keycode_config.h26
-rw-r--r--quantum/keymap.h350
-rw-r--r--quantum/keymap_common.c322
-rw-r--r--quantum/keymap_common.h214
-rw-r--r--quantum/keymap_extras/keymap_bepo.h311
-rw-r--r--quantum/keymap_extras/keymap_canadian_multilingual.h255
-rw-r--r--quantum/keymap_extras/keymap_colemak.h2
-rw-r--r--quantum/keymap_extras/keymap_dvorak.h21
-rw-r--r--quantum/keymap_extras/keymap_dvp.h82
-rw-r--r--quantum/keymap_extras/keymap_fr_ch.h98
-rw-r--r--quantum/keymap_extras/keymap_french.h8
-rw-r--r--quantum/keymap_extras/keymap_french_osx.h2
-rw-r--r--quantum/keymap_extras/keymap_german.h4
-rw-r--r--quantum/keymap_extras/keymap_german_ch.h102
-rw-r--r--quantum/keymap_extras/keymap_german_osx.h161
-rw-r--r--quantum/keymap_extras/keymap_neo2.h23
-rw-r--r--quantum/keymap_extras/keymap_nordic.h6
-rw-r--r--quantum/keymap_extras/keymap_norwegian.h41
-rw-r--r--quantum/keymap_extras/keymap_plover.h32
-rw-r--r--quantum/keymap_extras/keymap_russian.h77
-rw-r--r--quantum/keymap_extras/keymap_spanish.h8
-rw-r--r--quantum/keymap_extras/keymap_uk.h6
-rw-r--r--quantum/keymap_extras/keymap_unicode_cyrillic.h163
-rw-r--r--quantum/keymap_midi.c109
-rw-r--r--quantum/keymap_unicode.c61
-rw-r--r--quantum/led.c38
-rwxr-xr-xquantum/light_ws2812.c25
-rw-r--r--quantum/matrix.c206
-rw-r--r--quantum/process_keycode/process_chording.c60
-rw-r--r--quantum/process_keycode/process_chording.h16
-rw-r--r--quantum/process_keycode/process_leader.c38
-rw-r--r--quantum/process_keycode/process_leader.h23
-rw-r--r--quantum/process_keycode/process_midi.c68
-rw-r--r--quantum/process_keycode/process_midi.h (renamed from quantum/keymap_midi.h)35
-rw-r--r--quantum/process_keycode/process_music.c176
-rw-r--r--quantum/process_keycode/process_music.h27
-rw-r--r--quantum/process_keycode/process_tap_dance.c136
-rw-r--r--quantum/process_keycode/process_tap_dance.h72
-rw-r--r--quantum/process_keycode/process_unicode.c264
-rw-r--r--quantum/process_keycode/process_unicode.h166
-rw-r--r--quantum/quantum.c853
-rw-r--r--quantum/quantum.h113
-rw-r--r--quantum/quantum.mk53
-rw-r--r--quantum/rgblight.c757
-rw-r--r--quantum/rgblight.h18
-rw-r--r--quantum/serial_link/LICENSE21
-rw-r--r--quantum/serial_link/README.md1
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c142
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.h37
-rw-r--r--quantum/serial_link/protocol/frame_router.c69
-rw-r--r--quantum/serial_link/protocol/frame_router.h38
-rw-r--r--quantum/serial_link/protocol/frame_validator.c121
-rw-r--r--quantum/serial_link/protocol/frame_validator.h34
-rw-r--r--quantum/serial_link/protocol/physical.h30
-rw-r--r--quantum/serial_link/protocol/transport.c128
-rw-r--r--quantum/serial_link/protocol/transport.h152
-rw-r--r--quantum/serial_link/protocol/triple_buffered_object.c78
-rw-r--r--quantum/serial_link/protocol/triple_buffered_object.h51
-rw-r--r--quantum/serial_link/system/serial_link.c265
-rw-r--r--quantum/serial_link/system/serial_link.h63
-rw-r--r--quantum/serial_link/tests/Makefile61
-rw-r--r--quantum/serial_link/tests/byte_stuffer_tests.cpp483
-rw-r--r--quantum/serial_link/tests/frame_router_tests.cpp229
-rw-r--r--quantum/serial_link/tests/frame_validator_tests.cpp115
-rw-r--r--quantum/serial_link/tests/rules.mk22
-rw-r--r--quantum/serial_link/tests/testlist.mk6
-rw-r--r--quantum/serial_link/tests/transport_tests.cpp188
-rw-r--r--quantum/serial_link/tests/triple_buffered_object_tests.cpp84
-rw-r--r--quantum/template/Makefile142
-rw-r--r--quantum/template/config.h103
-rw-r--r--quantum/template/keymaps/default/Makefile21
-rw-r--r--quantum/template/keymaps/default/config.h8
-rw-r--r--quantum/template/keymaps/default/keymap.c (renamed from quantum/template/keymaps/default.c)20
-rw-r--r--quantum/template/keymaps/default/readme.md1
-rw-r--r--quantum/template/readme.md (renamed from quantum/template/README.md)18
-rw-r--r--quantum/template/rules.mk67
-rw-r--r--quantum/template/template.c39
-rw-r--r--quantum/template/template.h14
-rw-r--r--quantum/tools/eeprom_reset.hex9
-rw-r--r--quantum/tools/readme.md6
-rw-r--r--quantum/variable_trace.c110
-rw-r--r--quantum/variable_trace.h34
-rw-r--r--quantum/visualizer/LICENSE.md29
-rw-r--r--quantum/visualizer/example_integration/callbacks.c36
-rw-r--r--quantum/visualizer/example_integration/gfxconf.h325
-rw-r--r--quantum/visualizer/example_integration/lcd_backlight_hal.c91
-rw-r--r--quantum/visualizer/example_integration/visualizer_user.c121
-rw-r--r--quantum/visualizer/lcd_backlight.c85
-rw-r--r--quantum/visualizer/lcd_backlight.h42
-rw-r--r--quantum/visualizer/led_test.c170
-rw-r--r--quantum/visualizer/led_test.h41
-rw-r--r--quantum/visualizer/readme.md18
-rw-r--r--quantum/visualizer/visualizer.c545
-rw-r--r--quantum/visualizer/visualizer.h147
-rw-r--r--quantum/visualizer/visualizer.mk61
110 files changed, 11381 insertions, 1924 deletions
diff --git a/quantum/audio.c b/quantum/audio.c
deleted file mode 100644
index 3a3a1a491..000000000
--- a/quantum/audio.c
+++ /dev/null
@@ -1,362 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <math.h>
4#include <avr/pgmspace.h>
5#include <avr/interrupt.h>
6#include <avr/io.h>
7
8#include "audio.h"
9#include "keymap_common.h"
10
11#define PI 3.14159265
12
13// #define PWM_AUDIO
14
15#ifdef PWM_AUDIO
16 #include "wave.h"
17 #define SAMPLE_DIVIDER 39
18 #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048)
19 // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
20#endif
21
22void delay_us(int count) {
23 while(count--) {
24 _delay_us(1);
25 }
26}
27
28int voices = 0;
29int voice_place = 0;
30double frequency = 0;
31int volume = 0;
32long position = 0;
33
34double frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
35int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
36bool sliding = false;
37
38int max = 0xFF;
39float sum = 0;
40int value = 128;
41float place = 0;
42float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
43
44uint16_t place_int = 0;
45bool repeat = true;
46uint8_t * sample;
47uint16_t sample_length = 0;
48
49
50bool notes = false;
51bool note = false;
52float note_frequency = 0;
53float note_length = 0;
54uint16_t note_position = 0;
55float (* notes_pointer)[][2];
56uint8_t notes_length;
57bool notes_repeat;
58uint8_t current_note = 0;
59
60void stop_all_notes() {
61 voices = 0;
62 #ifdef PWM_AUDIO
63 TIMSK3 &= ~_BV(OCIE3A);
64 #else
65 TIMSK3 &= ~_BV(OCIE3A);
66 TCCR3A &= ~_BV(COM3A1);
67 #endif
68 notes = false;
69 note = false;
70 frequency = 0;
71 volume = 0;
72
73 for (int i = 0; i < 8; i++) {
74 frequencies[i] = 0;
75 volumes[i] = 0;
76 }
77}
78
79void stop_note(double freq) {
80 #ifdef PWM_AUDIO
81 freq = freq / SAMPLE_RATE;
82 #endif
83 for (int i = 7; i >= 0; i--) {
84 if (frequencies[i] == freq) {
85 frequencies[i] = 0;
86 volumes[i] = 0;
87 for (int j = i; (j < 7); j++) {
88 frequencies[j] = frequencies[j+1];
89 frequencies[j+1] = 0;
90 volumes[j] = volumes[j+1];
91 volumes[j+1] = 0;
92 }
93 }
94 }
95 voices--;
96 if (voices < 0)
97 voices = 0;
98 if (voices == 0) {
99 #ifdef PWM_AUDIO
100 TIMSK3 &= ~_BV(OCIE3A);
101 #else
102 TIMSK3 &= ~_BV(OCIE3A);
103 TCCR3A &= ~_BV(COM3A1);
104 #endif
105 frequency = 0;
106 volume = 0;
107 note = false;
108 } else {
109 double freq = frequencies[voices - 1];
110 int vol = volumes[voices - 1];
111 double starting_f = frequency;
112 if (frequency < freq) {
113 sliding = true;
114 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {
115 frequency = f;
116 }
117 sliding = false;
118 } else if (frequency > freq) {
119 sliding = true;
120 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
121 frequency = f;
122 }
123 sliding = false;
124 }
125 frequency = freq;
126 volume = vol;
127 }
128}
129
130void init_notes() {
131
132 #ifdef PWM_AUDIO
133 PLLFRQ = _BV(PDIV2);
134 PLLCSR = _BV(PLLE);
135 while(!(PLLCSR & _BV(PLOCK)));
136 PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
137
138 /* Init a fast PWM on Timer4 */
139 TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
140 TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
141 OCR4A = 0;
142
143 /* Enable the OC4A output */
144 DDRC |= _BV(PORTC6);
145
146 TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
147
148 TCCR3A = 0x0; // Options not needed
149 TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
150 OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
151 #else
152 DDRC |= _BV(PORTC6);
153
154 TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs
155
156 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
157 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
158 #endif
159}
160
161
162ISR(TIMER3_COMPA_vect) {
163
164 if (note) {
165 #ifdef PWM_AUDIO
166 if (voices == 1) {
167 // SINE
168 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
169
170 // SQUARE
171 // if (((int)place) >= 1024){
172 // OCR4A = 0xFF >> 2;
173 // } else {
174 // OCR4A = 0x00;
175 // }
176
177 // SAWTOOTH
178 // OCR4A = (int)place / 4;
179
180 // TRIANGLE
181 // if (((int)place) >= 1024) {
182 // OCR4A = (int)place / 2;
183 // } else {
184 // OCR4A = 2048 - (int)place / 2;
185 // }
186
187 place += frequency;
188
189 if (place >= SINE_LENGTH)
190 place -= SINE_LENGTH;
191
192 } else {
193 int sum = 0;
194 for (int i = 0; i < voices; i++) {
195 // SINE
196 sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
197
198 // SQUARE
199 // if (((int)places[i]) >= 1024){
200 // sum += 0xFF >> 2;
201 // } else {
202 // sum += 0x00;
203 // }
204
205 places[i] += frequencies[i];
206
207 if (places[i] >= SINE_LENGTH)
208 places[i] -= SINE_LENGTH;
209 }
210 OCR4A = sum;
211 }
212 #else
213 if (frequency > 0) {
214 // ICR3 = (int)(((double)F_CPU) / frequency); // Set max to the period
215 // OCR3A = (int)(((double)F_CPU) / frequency) >> 1; // Set compare to half the period
216 if (place > 10) {
217 voice_place = (voice_place + 1) % voices;
218 place = 0.0;
219 }
220 ICR3 = (int)(((double)F_CPU) / frequencies[voice_place]); // Set max to the period
221 OCR3A = (int)(((double)F_CPU) / frequencies[voice_place]) >> 1; // Set compare to half the period
222 place++;
223 }
224 #endif
225 }
226
227 // SAMPLE
228 // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
229
230 // place_int++;
231
232 // if (place_int >= sample_length)
233 // if (repeat)
234 // place_int -= sample_length;
235 // else
236 // TIMSK3 &= ~_BV(OCIE3A);
237
238
239 if (notes) {
240 #ifdef PWM_AUDIO
241 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
242
243 place += note_frequency;
244 if (place >= SINE_LENGTH)
245 place -= SINE_LENGTH;
246 #else
247 if (note_frequency > 0) {
248 ICR3 = (int)(((double)F_CPU) / note_frequency); // Set max to the period
249 OCR3A = (int)(((double)F_CPU) / note_frequency) >> 1; // Set compare to half the period
250 }
251 #endif
252
253
254 note_position++;
255 if (note_position >= note_length) {
256 current_note++;
257 if (current_note >= notes_length) {
258 if (notes_repeat) {
259 current_note = 0;
260 } else {
261 #ifdef PWM_AUDIO
262 TIMSK3 &= ~_BV(OCIE3A);
263 #else
264 TIMSK3 &= ~_BV(OCIE3A);
265 TCCR3A &= ~_BV(COM3A1);
266 #endif
267 notes = false;
268 return;
269 }
270 }
271 #ifdef PWM_AUDIO
272 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
273 note_length = (*notes_pointer)[current_note][1];
274 #else
275 note_frequency = (*notes_pointer)[current_note][0];
276 note_length = (*notes_pointer)[current_note][1] / 4;
277 #endif
278 note_position = 0;
279 }
280
281 }
282
283}
284
285void play_notes(float (*np)[][2], uint8_t n_length, bool n_repeat) {
286 if (note)
287 stop_all_notes();
288 notes = true;
289
290 notes_pointer = np;
291 notes_length = n_length;
292 notes_repeat = n_repeat;
293
294 place = 0;
295 current_note = 0;
296 #ifdef PWM_AUDIO
297 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
298 note_length = (*notes_pointer)[current_note][1];
299 #else
300 note_frequency = (*notes_pointer)[current_note][0];
301 note_length = (*notes_pointer)[current_note][1] / 4;
302 #endif
303 note_position = 0;
304
305
306 #ifdef PWM_AUDIO
307 TIMSK3 |= _BV(OCIE3A);
308 #else
309 TIMSK3 |= _BV(OCIE3A);
310 TCCR3A |= _BV(COM3A1);
311 #endif
312}
313
314void play_sample(uint8_t * s, uint16_t l, bool r) {
315 stop_all_notes();
316 place_int = 0;
317 sample = s;
318 sample_length = l;
319 repeat = r;
320
321 #ifdef PWM_AUDIO
322 TIMSK3 |= _BV(OCIE3A);
323 #else
324 #endif
325}
326
327void play_note(double freq, int vol) {
328 if (notes)
329 stop_all_notes();
330 note = true;
331 #ifdef PWM_AUDIO
332 freq = freq / SAMPLE_RATE;
333 #endif
334 if (freq > 0) {
335 if (frequency != 0) {
336 double starting_f = frequency;
337 if (frequency < freq) {
338 for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) {
339 frequency = f;
340 }
341 } else if (frequency > freq) {
342 for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) {
343 frequency = f;
344 }
345 }
346 }
347 frequency = freq;
348 volume = vol;
349
350 frequencies[voices] = frequency;
351 volumes[voices] = volume;
352 voices++;
353 }
354
355 #ifdef PWM_AUDIO
356 TIMSK3 |= _BV(OCIE3A);
357 #else
358 TIMSK3 |= _BV(OCIE3A);
359 TCCR3A |= _BV(COM3A1);
360 #endif
361
362} \ No newline at end of file
diff --git a/quantum/audio.h b/quantum/audio.h
deleted file mode 100644
index 99203cea7..000000000
--- a/quantum/audio.h
+++ /dev/null
@@ -1,11 +0,0 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include <avr/io.h>
4#include <util/delay.h>
5
6void play_sample(uint8_t * s, uint16_t l, bool r);
7void play_note(double freq, int vol);
8void stop_note(double freq);
9void stop_all_notes();
10void init_notes();
11void play_notes(float (*np)[][2], uint8_t n_length, bool n_repeat); \ No newline at end of file
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c
new file mode 100644
index 000000000..ead5fbf3e
--- /dev/null
+++ b/quantum/audio/audio.c
@@ -0,0 +1,477 @@
1#include <stdio.h>
2#include <string.h>
3//#include <math.h>
4#include <avr/pgmspace.h>
5#include <avr/interrupt.h>
6#include <avr/io.h>
7#include "print.h"
8#include "audio.h"
9#include "keymap.h"
10
11#include "eeconfig.h"
12
13#define CPU_PRESCALER 8
14
15// -----------------------------------------------------------------------------
16// Timer Abstractions
17// -----------------------------------------------------------------------------
18
19// TIMSK3 - Timer/Counter #3 Interrupt Mask Register
20// Turn on/off 3A interputs, stopping/enabling the ISR calls
21#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
22#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
23
24// TCCR3A: Timer/Counter #3 Control Register
25// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
26#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
27#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
28
29// Fast PWM Mode Controls
30#define TIMER_3_PERIOD ICR3
31#define TIMER_3_DUTY_CYCLE OCR3A
32
33// -----------------------------------------------------------------------------
34
35
36int voices = 0;
37int voice_place = 0;
38float frequency = 0;
39int volume = 0;
40long position = 0;
41
42float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
43int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
44bool sliding = false;
45
46float place = 0;
47
48uint8_t * sample;
49uint16_t sample_length = 0;
50
51bool playing_notes = false;
52bool playing_note = false;
53float note_frequency = 0;
54float note_length = 0;
55uint8_t note_tempo = TEMPO_DEFAULT;
56float note_timbre = TIMBRE_DEFAULT;
57uint16_t note_position = 0;
58float (* notes_pointer)[][2];
59uint16_t notes_count;
60bool notes_repeat;
61float notes_rest;
62bool note_resting = false;
63
64uint8_t current_note = 0;
65uint8_t rest_counter = 0;
66
67#ifdef VIBRATO_ENABLE
68float vibrato_counter = 0;
69float vibrato_strength = .5;
70float vibrato_rate = 0.125;
71#endif
72
73float polyphony_rate = 0;
74
75static bool audio_initialized = false;
76
77audio_config_t audio_config;
78
79uint16_t envelope_index = 0;
80
81void audio_init()
82{
83
84 // Check EEPROM
85 if (!eeconfig_is_enabled())
86 {
87 eeconfig_init();
88 }
89 audio_config.raw = eeconfig_read_audio();
90
91 // Set port PC6 (OC3A and /OC4A) as output
92 DDRC |= _BV(PORTC6);
93
94 DISABLE_AUDIO_COUNTER_3_ISR;
95
96 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
97 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
98 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
99 // Clock Select (CS3n) = 0b010 = Clock / 8
100 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
101 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
102
103 audio_initialized = true;
104}
105
106void stop_all_notes()
107{
108 if (!audio_initialized) {
109 audio_init();
110 }
111 voices = 0;
112
113 DISABLE_AUDIO_COUNTER_3_ISR;
114 DISABLE_AUDIO_COUNTER_3_OUTPUT;
115
116 playing_notes = false;
117 playing_note = false;
118 frequency = 0;
119 volume = 0;
120
121 for (uint8_t i = 0; i < 8; i++)
122 {
123 frequencies[i] = 0;
124 volumes[i] = 0;
125 }
126}
127
128void stop_note(float freq)
129{
130 if (playing_note) {
131 if (!audio_initialized) {
132 audio_init();
133 }
134 for (int i = 7; i >= 0; i--) {
135 if (frequencies[i] == freq) {
136 frequencies[i] = 0;
137 volumes[i] = 0;
138 for (int j = i; (j < 7); j++) {
139 frequencies[j] = frequencies[j+1];
140 frequencies[j+1] = 0;
141 volumes[j] = volumes[j+1];
142 volumes[j+1] = 0;
143 }
144 break;
145 }
146 }
147 voices--;
148 if (voices < 0)
149 voices = 0;
150 if (voice_place >= voices) {
151 voice_place = 0;
152 }
153 if (voices == 0) {
154 DISABLE_AUDIO_COUNTER_3_ISR;
155 DISABLE_AUDIO_COUNTER_3_OUTPUT;
156 frequency = 0;
157 volume = 0;
158 playing_note = false;
159 }
160 }
161}
162
163#ifdef VIBRATO_ENABLE
164
165float mod(float a, int b)
166{
167 float r = fmod(a, b);
168 return r < 0 ? r + b : r;
169}
170
171float vibrato(float average_freq) {
172 #ifdef VIBRATO_STRENGTH_ENABLE
173 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
174 #else
175 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
176 #endif
177 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH);
178 return vibrated_freq;
179}
180
181#endif
182
183ISR(TIMER3_COMPA_vect)
184{
185 float freq;
186
187 if (playing_note) {
188 if (voices > 0) {
189 if (polyphony_rate > 0) {
190 if (voices > 1) {
191 voice_place %= voices;
192 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
193 voice_place = (voice_place + 1) % voices;
194 place = 0.0;
195 }
196 }
197
198 #ifdef VIBRATO_ENABLE
199 if (vibrato_strength > 0) {
200 freq = vibrato(frequencies[voice_place]);
201 } else {
202 freq = frequencies[voice_place];
203 }
204 #else
205 freq = frequencies[voice_place];
206 #endif
207 } else {
208 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
209 frequency = frequency * pow(2, 440/frequency/12/2);
210 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
211 frequency = frequency * pow(2, -440/frequency/12/2);
212 } else {
213 frequency = frequencies[voices - 1];
214 }
215
216 #ifdef VIBRATO_ENABLE
217 if (vibrato_strength > 0) {
218 freq = vibrato(frequency);
219 } else {
220 freq = frequency;
221 }
222 #else
223 freq = frequency;
224 #endif
225 }
226
227 if (envelope_index < 65535) {
228 envelope_index++;
229 }
230
231 freq = voice_envelope(freq);
232
233 if (freq < 30.517578125) {
234 freq = 30.52;
235 }
236
237 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
238 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
239 }
240 }
241
242 if (playing_notes) {
243 if (note_frequency > 0) {
244 #ifdef VIBRATO_ENABLE
245 if (vibrato_strength > 0) {
246 freq = vibrato(note_frequency);
247 } else {
248 freq = note_frequency;
249 }
250 #else
251 freq = note_frequency;
252 #endif
253
254 if (envelope_index < 65535) {
255 envelope_index++;
256 }
257 freq = voice_envelope(freq);
258
259 TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
260 TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre);
261 } else {
262 TIMER_3_PERIOD = 0;
263 TIMER_3_DUTY_CYCLE = 0;
264 }
265
266 note_position++;
267 bool end_of_note = false;
268 if (TIMER_3_PERIOD > 0) {
269 end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF));
270 } else {
271 end_of_note = (note_position >= (note_length * 0x7FF));
272 }
273
274 if (end_of_note) {
275 current_note++;
276 if (current_note >= notes_count) {
277 if (notes_repeat) {
278 current_note = 0;
279 } else {
280 DISABLE_AUDIO_COUNTER_3_ISR;
281 DISABLE_AUDIO_COUNTER_3_OUTPUT;
282 playing_notes = false;
283 return;
284 }
285 }
286 if (!note_resting && (notes_rest > 0)) {
287 note_resting = true;
288 note_frequency = 0;
289 note_length = notes_rest;
290 current_note--;
291 } else {
292 note_resting = false;
293 envelope_index = 0;
294 note_frequency = (*notes_pointer)[current_note][0];
295 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
296 }
297
298 note_position = 0;
299 }
300 }
301
302 if (!audio_config.enable) {
303 playing_notes = false;
304 playing_note = false;
305 }
306}
307
308void play_note(float freq, int vol) {
309
310 if (!audio_initialized) {
311 audio_init();
312 }
313
314 if (audio_config.enable && voices < 8) {
315 DISABLE_AUDIO_COUNTER_3_ISR;
316
317 // Cancel notes if notes are playing
318 if (playing_notes)
319 stop_all_notes();
320
321 playing_note = true;
322
323 envelope_index = 0;
324
325 if (freq > 0) {
326 frequencies[voices] = freq;
327 volumes[voices] = vol;
328 voices++;
329 }
330
331 ENABLE_AUDIO_COUNTER_3_ISR;
332 ENABLE_AUDIO_COUNTER_3_OUTPUT;
333 }
334
335}
336
337void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
338{
339
340 if (!audio_initialized) {
341 audio_init();
342 }
343
344 if (audio_config.enable) {
345
346 DISABLE_AUDIO_COUNTER_3_ISR;
347
348 // Cancel note if a note is playing
349 if (playing_note)
350 stop_all_notes();
351
352 playing_notes = true;
353
354 notes_pointer = np;
355 notes_count = n_count;
356 notes_repeat = n_repeat;
357 notes_rest = n_rest;
358
359 place = 0;
360 current_note = 0;
361
362 note_frequency = (*notes_pointer)[current_note][0];
363 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
364 note_position = 0;
365
366
367 ENABLE_AUDIO_COUNTER_3_ISR;
368 ENABLE_AUDIO_COUNTER_3_OUTPUT;
369 }
370
371}
372
373bool is_playing_notes(void) {
374 return playing_notes;
375}
376
377bool is_audio_on(void) {
378 return (audio_config.enable != 0);
379}
380
381void audio_toggle(void) {
382 audio_config.enable ^= 1;
383 eeconfig_update_audio(audio_config.raw);
384 if (audio_config.enable)
385 audio_on_user();
386}
387
388void audio_on(void) {
389 audio_config.enable = 1;
390 eeconfig_update_audio(audio_config.raw);
391 audio_on_user();
392}
393
394void audio_off(void) {
395 audio_config.enable = 0;
396 eeconfig_update_audio(audio_config.raw);
397}
398
399#ifdef VIBRATO_ENABLE
400
401// Vibrato rate functions
402
403void set_vibrato_rate(float rate) {
404 vibrato_rate = rate;
405}
406
407void increase_vibrato_rate(float change) {
408 vibrato_rate *= change;
409}
410
411void decrease_vibrato_rate(float change) {
412 vibrato_rate /= change;
413}
414
415#ifdef VIBRATO_STRENGTH_ENABLE
416
417void set_vibrato_strength(float strength) {
418 vibrato_strength = strength;
419}
420
421void increase_vibrato_strength(float change) {
422 vibrato_strength *= change;
423}
424
425void decrease_vibrato_strength(float change) {
426 vibrato_strength /= change;
427}
428
429#endif /* VIBRATO_STRENGTH_ENABLE */
430
431#endif /* VIBRATO_ENABLE */
432
433// Polyphony functions
434
435void set_polyphony_rate(float rate) {
436 polyphony_rate = rate;
437}
438
439void enable_polyphony() {
440 polyphony_rate = 5;
441}
442
443void disable_polyphony() {
444 polyphony_rate = 0;
445}
446
447void increase_polyphony_rate(float change) {
448 polyphony_rate *= change;
449}
450
451void decrease_polyphony_rate(float change) {
452 polyphony_rate /= change;
453}
454
455// Timbre function
456
457void set_timbre(float timbre) {
458 note_timbre = timbre;
459}
460
461// Tempo functions
462
463void set_tempo(uint8_t tempo) {
464 note_tempo = tempo;
465}
466
467void decrease_tempo(uint8_t tempo_change) {
468 note_tempo += tempo_change;
469}
470
471void increase_tempo(uint8_t tempo_change) {
472 if (note_tempo - tempo_change < 10) {
473 note_tempo = 10;
474 } else {
475 note_tempo -= tempo_change;
476 }
477}
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
new file mode 100644
index 000000000..47f326ea0
--- /dev/null
+++ b/quantum/audio/audio.h
@@ -0,0 +1,91 @@
1#ifndef AUDIO_H
2#define AUDIO_H
3
4#include <stdint.h>
5#include <stdbool.h>
6#include <avr/io.h>
7#include <util/delay.h>
8#include "musical_notes.h"
9#include "song_list.h"
10#include "voices.h"
11#include "quantum.h"
12
13// Largely untested PWM audio mode (doesn't sound as good)
14// #define PWM_AUDIO
15
16// #define VIBRATO_ENABLE
17
18// Enable vibrato strength/amplitude - slows down ISR too much
19// #define VIBRATO_STRENGTH_ENABLE
20
21typedef union {
22 uint8_t raw;
23 struct {
24 bool enable :1;
25 uint8_t level :7;
26 };
27} audio_config_t;
28
29bool is_audio_on(void);
30void audio_toggle(void);
31void audio_on(void);
32void audio_off(void);
33
34// Vibrato rate functions
35
36#ifdef VIBRATO_ENABLE
37
38void set_vibrato_rate(float rate);
39void increase_vibrato_rate(float change);
40void decrease_vibrato_rate(float change);
41
42#ifdef VIBRATO_STRENGTH_ENABLE
43
44void set_vibrato_strength(float strength);
45void increase_vibrato_strength(float change);
46void decrease_vibrato_strength(float change);
47
48#endif
49
50#endif
51
52// Polyphony functions
53
54void set_polyphony_rate(float rate);
55void enable_polyphony(void);
56void disable_polyphony(void);
57void increase_polyphony_rate(float change);
58void decrease_polyphony_rate(float change);
59
60void set_timbre(float timbre);
61void set_tempo(uint8_t tempo);
62
63void increase_tempo(uint8_t tempo_change);
64void decrease_tempo(uint8_t tempo_change);
65
66void audio_init(void);
67
68#ifdef PWM_AUDIO
69void play_sample(uint8_t * s, uint16_t l, bool r);
70#endif
71void play_note(float freq, int vol);
72void stop_note(float freq);
73void stop_all_notes(void);
74void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest);
75
76#define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \
77 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \
78 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \
79 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \
80 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), }
81
82// These macros are used to allow play_notes to play an array of indeterminate
83// length. This works around the limitation of C's sizeof operation on pointers.
84// The global float array for the song must be used here.
85#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0]))))
86#define PLAY_NOTE_ARRAY(note_array, note_repeat, note_rest_style) play_notes(&note_array, NOTE_ARRAY_SIZE((note_array)), (note_repeat), (note_rest_style));
87
88
89bool is_playing_notes(void);
90
91#endif \ No newline at end of file
diff --git a/quantum/audio/audio_pwm.c b/quantum/audio/audio_pwm.c
new file mode 100644
index 000000000..f820eec1b
--- /dev/null
+++ b/quantum/audio/audio_pwm.c
@@ -0,0 +1,643 @@
1#include <stdio.h>
2#include <string.h>
3//#include <math.h>
4#include <avr/pgmspace.h>
5#include <avr/interrupt.h>
6#include <avr/io.h>
7#include "print.h"
8#include "audio.h"
9#include "keymap.h"
10
11#include "eeconfig.h"
12
13#define PI 3.14159265
14
15#define CPU_PRESCALER 8
16
17
18// Timer Abstractions
19
20// TIMSK3 - Timer/Counter #3 Interrupt Mask Register
21// Turn on/off 3A interputs, stopping/enabling the ISR calls
22#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A)
23#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A)
24
25
26// TCCR3A: Timer/Counter #3 Control Register
27// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
28#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1);
29#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0));
30
31
32#define NOTE_PERIOD ICR3
33#define NOTE_DUTY_CYCLE OCR3A
34
35
36#ifdef PWM_AUDIO
37 #include "wave.h"
38 #define SAMPLE_DIVIDER 39
39 #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048)
40 // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap
41
42 float places[8] = {0, 0, 0, 0, 0, 0, 0, 0};
43 uint16_t place_int = 0;
44 bool repeat = true;
45#endif
46
47void delay_us(int count) {
48 while(count--) {
49 _delay_us(1);
50 }
51}
52
53int voices = 0;
54int voice_place = 0;
55float frequency = 0;
56int volume = 0;
57long position = 0;
58
59float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0};
60int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
61bool sliding = false;
62
63float place = 0;
64
65uint8_t * sample;
66uint16_t sample_length = 0;
67// float freq = 0;
68
69bool playing_notes = false;
70bool playing_note = false;
71float note_frequency = 0;
72float note_length = 0;
73uint8_t note_tempo = TEMPO_DEFAULT;
74float note_timbre = TIMBRE_DEFAULT;
75uint16_t note_position = 0;
76float (* notes_pointer)[][2];
77uint16_t notes_count;
78bool notes_repeat;
79float notes_rest;
80bool note_resting = false;
81
82uint8_t current_note = 0;
83uint8_t rest_counter = 0;
84
85#ifdef VIBRATO_ENABLE
86float vibrato_counter = 0;
87float vibrato_strength = .5;
88float vibrato_rate = 0.125;
89#endif
90
91float polyphony_rate = 0;
92
93static bool audio_initialized = false;
94
95audio_config_t audio_config;
96
97uint16_t envelope_index = 0;
98
99void audio_init() {
100
101 // Check EEPROM
102 if (!eeconfig_is_enabled())
103 {
104 eeconfig_init();
105 }
106 audio_config.raw = eeconfig_read_audio();
107
108 #ifdef PWM_AUDIO
109
110 PLLFRQ = _BV(PDIV2);
111 PLLCSR = _BV(PLLE);
112 while(!(PLLCSR & _BV(PLOCK)));
113 PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */
114
115 /* Init a fast PWM on Timer4 */
116 TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */
117 TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */
118 OCR4A = 0;
119
120 /* Enable the OC4A output */
121 DDRC |= _BV(PORTC6);
122
123 DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs
124
125 TCCR3A = 0x0; // Options not needed
126 TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC
127 OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback
128
129 #else
130
131 // Set port PC6 (OC3A and /OC4A) as output
132 DDRC |= _BV(PORTC6);
133
134 DISABLE_AUDIO_COUNTER_3_ISR;
135
136 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers
137 // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6
138 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A)
139 // Clock Select (CS3n) = 0b010 = Clock / 8
140 TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30);
141 TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30);
142
143 #endif
144
145 audio_initialized = true;
146}
147
148void stop_all_notes() {
149 if (!audio_initialized) {
150 audio_init();
151 }
152 voices = 0;
153 #ifdef PWM_AUDIO
154 DISABLE_AUDIO_COUNTER_3_ISR;
155 #else
156 DISABLE_AUDIO_COUNTER_3_ISR;
157 DISABLE_AUDIO_COUNTER_3_OUTPUT;
158 #endif
159
160 playing_notes = false;
161 playing_note = false;
162 frequency = 0;
163 volume = 0;
164
165 for (uint8_t i = 0; i < 8; i++)
166 {
167 frequencies[i] = 0;
168 volumes[i] = 0;
169 }
170}
171
172void stop_note(float freq)
173{
174 if (playing_note) {
175 if (!audio_initialized) {
176 audio_init();
177 }
178 #ifdef PWM_AUDIO
179 freq = freq / SAMPLE_RATE;
180 #endif
181 for (int i = 7; i >= 0; i--) {
182 if (frequencies[i] == freq) {
183 frequencies[i] = 0;
184 volumes[i] = 0;
185 for (int j = i; (j < 7); j++) {
186 frequencies[j] = frequencies[j+1];
187 frequencies[j+1] = 0;
188 volumes[j] = volumes[j+1];
189 volumes[j+1] = 0;
190 }
191 break;
192 }
193 }
194 voices--;
195 if (voices < 0)
196 voices = 0;
197 if (voice_place >= voices) {
198 voice_place = 0;
199 }
200 if (voices == 0) {
201 #ifdef PWM_AUDIO
202 DISABLE_AUDIO_COUNTER_3_ISR;
203 #else
204 DISABLE_AUDIO_COUNTER_3_ISR;
205 DISABLE_AUDIO_COUNTER_3_OUTPUT;
206 #endif
207 frequency = 0;
208 volume = 0;
209 playing_note = false;
210 }
211 }
212}
213
214#ifdef VIBRATO_ENABLE
215
216float mod(float a, int b)
217{
218 float r = fmod(a, b);
219 return r < 0 ? r + b : r;
220}
221
222float vibrato(float average_freq) {
223 #ifdef VIBRATO_STRENGTH_ENABLE
224 float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength);
225 #else
226 float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter];
227 #endif
228 vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH);
229 return vibrated_freq;
230}
231
232#endif
233
234ISR(TIMER3_COMPA_vect)
235{
236 if (playing_note) {
237 #ifdef PWM_AUDIO
238 if (voices == 1) {
239 // SINE
240 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2;
241
242 // SQUARE
243 // if (((int)place) >= 1024){
244 // OCR4A = 0xFF >> 2;
245 // } else {
246 // OCR4A = 0x00;
247 // }
248
249 // SAWTOOTH
250 // OCR4A = (int)place / 4;
251
252 // TRIANGLE
253 // if (((int)place) >= 1024) {
254 // OCR4A = (int)place / 2;
255 // } else {
256 // OCR4A = 2048 - (int)place / 2;
257 // }
258
259 place += frequency;
260
261 if (place >= SINE_LENGTH)
262 place -= SINE_LENGTH;
263
264 } else {
265 int sum = 0;
266 for (int i = 0; i < voices; i++) {
267 // SINE
268 sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2;
269
270 // SQUARE
271 // if (((int)places[i]) >= 1024){
272 // sum += 0xFF >> 2;
273 // } else {
274 // sum += 0x00;
275 // }
276
277 places[i] += frequencies[i];
278
279 if (places[i] >= SINE_LENGTH)
280 places[i] -= SINE_LENGTH;
281 }
282 OCR4A = sum;
283 }
284 #else
285 if (voices > 0) {
286 float freq;
287 if (polyphony_rate > 0) {
288 if (voices > 1) {
289 voice_place %= voices;
290 if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) {
291 voice_place = (voice_place + 1) % voices;
292 place = 0.0;
293 }
294 }
295 #ifdef VIBRATO_ENABLE
296 if (vibrato_strength > 0) {
297 freq = vibrato(frequencies[voice_place]);
298 } else {
299 #else
300 {
301 #endif
302 freq = frequencies[voice_place];
303 }
304 } else {
305 if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) {
306 frequency = frequency * pow(2, 440/frequency/12/2);
307 } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) {
308 frequency = frequency * pow(2, -440/frequency/12/2);
309 } else {
310 frequency = frequencies[voices - 1];
311 }
312
313
314 #ifdef VIBRATO_ENABLE
315 if (vibrato_strength > 0) {
316 freq = vibrato(frequency);
317 } else {
318 #else
319 {
320 #endif
321 freq = frequency;
322 }
323 }
324
325 if (envelope_index < 65535) {
326 envelope_index++;
327 }
328 freq = voice_envelope(freq);
329
330 if (freq < 30.517578125)
331 freq = 30.52;
332 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
333 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
334 }
335 #endif
336 }
337
338 // SAMPLE
339 // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]);
340
341 // place_int++;
342
343 // if (place_int >= sample_length)
344 // if (repeat)
345 // place_int -= sample_length;
346 // else
347 // DISABLE_AUDIO_COUNTER_3_ISR;
348
349
350 if (playing_notes) {
351 #ifdef PWM_AUDIO
352 OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0;
353
354 place += note_frequency;
355 if (place >= SINE_LENGTH)
356 place -= SINE_LENGTH;
357 #else
358 if (note_frequency > 0) {
359 float freq;
360
361 #ifdef VIBRATO_ENABLE
362 if (vibrato_strength > 0) {
363 freq = vibrato(note_frequency);
364 } else {
365 #else
366 {
367 #endif
368 freq = note_frequency;
369 }
370
371 if (envelope_index < 65535) {
372 envelope_index++;
373 }
374 freq = voice_envelope(freq);
375
376 NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period
377 NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period
378 } else {
379 NOTE_PERIOD = 0;
380 NOTE_DUTY_CYCLE = 0;
381 }
382 #endif
383
384
385 note_position++;
386 bool end_of_note = false;
387 if (NOTE_PERIOD > 0)
388 end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF));
389 else
390 end_of_note = (note_position >= (note_length * 0x7FF));
391 if (end_of_note) {
392 current_note++;
393 if (current_note >= notes_count) {
394 if (notes_repeat) {
395 current_note = 0;
396 } else {
397 #ifdef PWM_AUDIO
398 DISABLE_AUDIO_COUNTER_3_ISR;
399 #else
400 DISABLE_AUDIO_COUNTER_3_ISR;
401 DISABLE_AUDIO_COUNTER_3_OUTPUT;
402 #endif
403 playing_notes = false;
404 return;
405 }
406 }
407 if (!note_resting && (notes_rest > 0)) {
408 note_resting = true;
409 note_frequency = 0;
410 note_length = notes_rest;
411 current_note--;
412 } else {
413 note_resting = false;
414 #ifdef PWM_AUDIO
415 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
416 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
417 #else
418 envelope_index = 0;
419 note_frequency = (*notes_pointer)[current_note][0];
420 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
421 #endif
422 }
423 note_position = 0;
424 }
425
426 }
427
428 if (!audio_config.enable) {
429 playing_notes = false;
430 playing_note = false;
431 }
432}
433
434void play_note(float freq, int vol) {
435
436 if (!audio_initialized) {
437 audio_init();
438 }
439
440 if (audio_config.enable && voices < 8) {
441 DISABLE_AUDIO_COUNTER_3_ISR;
442
443 // Cancel notes if notes are playing
444 if (playing_notes)
445 stop_all_notes();
446
447 playing_note = true;
448
449 envelope_index = 0;
450
451 #ifdef PWM_AUDIO
452 freq = freq / SAMPLE_RATE;
453 #endif
454 if (freq > 0) {
455 frequencies[voices] = freq;
456 volumes[voices] = vol;
457 voices++;
458 }
459
460 #ifdef PWM_AUDIO
461 ENABLE_AUDIO_COUNTER_3_ISR;
462 #else
463 ENABLE_AUDIO_COUNTER_3_ISR;
464 ENABLE_AUDIO_COUNTER_3_OUTPUT;
465 #endif
466 }
467
468}
469
470void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest)
471{
472
473 if (!audio_initialized) {
474 audio_init();
475 }
476
477 if (audio_config.enable) {
478
479 DISABLE_AUDIO_COUNTER_3_ISR;
480
481 // Cancel note if a note is playing
482 if (playing_note)
483 stop_all_notes();
484
485 playing_notes = true;
486
487 notes_pointer = np;
488 notes_count = n_count;
489 notes_repeat = n_repeat;
490 notes_rest = n_rest;
491
492 place = 0;
493 current_note = 0;
494
495 #ifdef PWM_AUDIO
496 note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE;
497 note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100);
498 #else
499 note_frequency = (*notes_pointer)[current_note][0];
500 note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100);
501 #endif
502 note_position = 0;
503
504
505 #ifdef PWM_AUDIO
506 ENABLE_AUDIO_COUNTER_3_ISR;
507 #else
508 ENABLE_AUDIO_COUNTER_3_ISR;
509 ENABLE_AUDIO_COUNTER_3_OUTPUT;
510 #endif
511 }
512
513}
514
515#ifdef PWM_AUDIO
516void play_sample(uint8_t * s, uint16_t l, bool r) {
517 if (!audio_initialized) {
518 audio_init();
519 }
520
521 if (audio_config.enable) {
522 DISABLE_AUDIO_COUNTER_3_ISR;
523 stop_all_notes();
524 place_int = 0;
525 sample = s;
526 sample_length = l;
527 repeat = r;
528
529 ENABLE_AUDIO_COUNTER_3_ISR;
530 }
531}
532#endif
533
534
535void audio_toggle(void) {
536 audio_config.enable ^= 1;
537 eeconfig_update_audio(audio_config.raw);
538}
539
540void audio_on(void) {
541 audio_config.enable = 1;
542 eeconfig_update_audio(audio_config.raw);
543}
544
545void audio_off(void) {
546 audio_config.enable = 0;
547 eeconfig_update_audio(audio_config.raw);
548}
549
550#ifdef VIBRATO_ENABLE
551
552// Vibrato rate functions
553
554void set_vibrato_rate(float rate) {
555 vibrato_rate = rate;
556}
557
558void increase_vibrato_rate(float change) {
559 vibrato_rate *= change;
560}
561
562void decrease_vibrato_rate(float change) {
563 vibrato_rate /= change;
564}
565
566#ifdef VIBRATO_STRENGTH_ENABLE
567
568void set_vibrato_strength(float strength) {
569 vibrato_strength = strength;
570}
571
572void increase_vibrato_strength(float change) {
573 vibrato_strength *= change;
574}
575
576void decrease_vibrato_strength(float change) {
577 vibrato_strength /= change;
578}
579
580#endif /* VIBRATO_STRENGTH_ENABLE */
581
582#endif /* VIBRATO_ENABLE */
583
584// Polyphony functions
585
586void set_polyphony_rate(float rate) {
587 polyphony_rate = rate;
588}
589
590void enable_polyphony() {
591 polyphony_rate = 5;
592}
593
594void disable_polyphony() {
595 polyphony_rate = 0;
596}
597
598void increase_polyphony_rate(float change) {
599 polyphony_rate *= change;
600}
601
602void decrease_polyphony_rate(float change) {
603 polyphony_rate /= change;
604}
605
606// Timbre function
607
608void set_timbre(float timbre) {
609 note_timbre = timbre;
610}
611
612// Tempo functions
613
614void set_tempo(uint8_t tempo) {
615 note_tempo = tempo;
616}
617
618void decrease_tempo(uint8_t tempo_change) {
619 note_tempo += tempo_change;
620}
621
622void increase_tempo(uint8_t tempo_change) {
623 if (note_tempo - tempo_change < 10) {
624 note_tempo = 10;
625 } else {
626 note_tempo -= tempo_change;
627 }
628}
629
630
631//------------------------------------------------------------------------------
632// Override these functions in your keymap file to play different tunes on
633// startup and bootloader jump
634__attribute__ ((weak))
635void play_startup_tone()
636{
637}
638
639__attribute__ ((weak))
640void play_goodbye_tone()
641{
642}
643//------------------------------------------------------------------------------
diff --git a/quantum/audio/luts.c b/quantum/audio/luts.c
new file mode 100644
index 000000000..9f3de9a05
--- /dev/null
+++ b/quantum/audio/luts.c
@@ -0,0 +1,382 @@
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <avr/pgmspace.h>
4#include "luts.h"
5
6const float vibrato_lut[VIBRATO_LUT_LENGTH] =
7{
8 1.0022336811487,
9 1.0042529943610,
10 1.0058584256028,
11 1.0068905285205,
12 1.0072464122237,
13 1.0068905285205,
14 1.0058584256028,
15 1.0042529943610,
16 1.0022336811487,
17 1.0000000000000,
18 0.9977712970630,
19 0.9957650169978,
20 0.9941756956510,
21 0.9931566259436,
22 0.9928057204913,
23 0.9931566259436,
24 0.9941756956510,
25 0.9957650169978,
26 0.9977712970630,
27 1.0000000000000,
28};
29
30const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH] =
31{
32 0x8E0B,
33 0x8C02,
34 0x8A00,
35 0x8805,
36 0x8612,
37 0x8426,
38 0x8241,
39 0x8063,
40 0x7E8C,
41 0x7CBB,
42 0x7AF2,
43 0x792E,
44 0x7772,
45 0x75BB,
46 0x740B,
47 0x7261,
48 0x70BD,
49 0x6F20,
50 0x6D88,
51 0x6BF6,
52 0x6A69,
53 0x68E3,
54 0x6762,
55 0x65E6,
56 0x6470,
57 0x6300,
58 0x6194,
59 0x602E,
60 0x5ECD,
61 0x5D71,
62 0x5C1A,
63 0x5AC8,
64 0x597B,
65 0x5833,
66 0x56EF,
67 0x55B0,
68 0x5475,
69 0x533F,
70 0x520E,
71 0x50E1,
72 0x4FB8,
73 0x4E93,
74 0x4D73,
75 0x4C57,
76 0x4B3E,
77 0x4A2A,
78 0x491A,
79 0x480E,
80 0x4705,
81 0x4601,
82 0x4500,
83 0x4402,
84 0x4309,
85 0x4213,
86 0x4120,
87 0x4031,
88 0x3F46,
89 0x3E5D,
90 0x3D79,
91 0x3C97,
92 0x3BB9,
93 0x3ADD,
94 0x3A05,
95 0x3930,
96 0x385E,
97 0x3790,
98 0x36C4,
99 0x35FB,
100 0x3534,
101 0x3471,
102 0x33B1,
103 0x32F3,
104 0x3238,
105 0x3180,
106 0x30CA,
107 0x3017,
108 0x2F66,
109 0x2EB8,
110 0x2E0D,
111 0x2D64,
112 0x2CBD,
113 0x2C19,
114 0x2B77,
115 0x2AD8,
116 0x2A3A,
117 0x299F,
118 0x2907,
119 0x2870,
120 0x27DC,
121 0x2749,
122 0x26B9,
123 0x262B,
124 0x259F,
125 0x2515,
126 0x248D,
127 0x2407,
128 0x2382,
129 0x2300,
130 0x2280,
131 0x2201,
132 0x2184,
133 0x2109,
134 0x2090,
135 0x2018,
136 0x1FA3,
137 0x1F2E,
138 0x1EBC,
139 0x1E4B,
140 0x1DDC,
141 0x1D6E,
142 0x1D02,
143 0x1C98,
144 0x1C2F,
145 0x1BC8,
146 0x1B62,
147 0x1AFD,
148 0x1A9A,
149 0x1A38,
150 0x19D8,
151 0x1979,
152 0x191C,
153 0x18C0,
154 0x1865,
155 0x180B,
156 0x17B3,
157 0x175C,
158 0x1706,
159 0x16B2,
160 0x165E,
161 0x160C,
162 0x15BB,
163 0x156C,
164 0x151D,
165 0x14CF,
166 0x1483,
167 0x1438,
168 0x13EE,
169 0x13A4,
170 0x135C,
171 0x1315,
172 0x12CF,
173 0x128A,
174 0x1246,
175 0x1203,
176 0x11C1,
177 0x1180,
178 0x1140,
179 0x1100,
180 0x10C2,
181 0x1084,
182 0x1048,
183 0x100C,
184 0xFD1,
185 0xF97,
186 0xF5E,
187 0xF25,
188 0xEEE,
189 0xEB7,
190 0xE81,
191 0xE4C,
192 0xE17,
193 0xDE4,
194 0xDB1,
195 0xD7E,
196 0xD4D,
197 0xD1C,
198 0xCEC,
199 0xCBC,
200 0xC8E,
201 0xC60,
202 0xC32,
203 0xC05,
204 0xBD9,
205 0xBAE,
206 0xB83,
207 0xB59,
208 0xB2F,
209 0xB06,
210 0xADD,
211 0xAB6,
212 0xA8E,
213 0xA67,
214 0xA41,
215 0xA1C,
216 0x9F7,
217 0x9D2,
218 0x9AE,
219 0x98A,
220 0x967,
221 0x945,
222 0x923,
223 0x901,
224 0x8E0,
225 0x8C0,
226 0x8A0,
227 0x880,
228 0x861,
229 0x842,
230 0x824,
231 0x806,
232 0x7E8,
233 0x7CB,
234 0x7AF,
235 0x792,
236 0x777,
237 0x75B,
238 0x740,
239 0x726,
240 0x70B,
241 0x6F2,
242 0x6D8,
243 0x6BF,
244 0x6A6,
245 0x68E,
246 0x676,
247 0x65E,
248 0x647,
249 0x630,
250 0x619,
251 0x602,
252 0x5EC,
253 0x5D7,
254 0x5C1,
255 0x5AC,
256 0x597,
257 0x583,
258 0x56E,
259 0x55B,
260 0x547,
261 0x533,
262 0x520,
263 0x50E,
264 0x4FB,
265 0x4E9,
266 0x4D7,
267 0x4C5,
268 0x4B3,
269 0x4A2,
270 0x491,
271 0x480,
272 0x470,
273 0x460,
274 0x450,
275 0x440,
276 0x430,
277 0x421,
278 0x412,
279 0x403,
280 0x3F4,
281 0x3E5,
282 0x3D7,
283 0x3C9,
284 0x3BB,
285 0x3AD,
286 0x3A0,
287 0x393,
288 0x385,
289 0x379,
290 0x36C,
291 0x35F,
292 0x353,
293 0x347,
294 0x33B,
295 0x32F,
296 0x323,
297 0x318,
298 0x30C,
299 0x301,
300 0x2F6,
301 0x2EB,
302 0x2E0,
303 0x2D6,
304 0x2CB,
305 0x2C1,
306 0x2B7,
307 0x2AD,
308 0x2A3,
309 0x299,
310 0x290,
311 0x287,
312 0x27D,
313 0x274,
314 0x26B,
315 0x262,
316 0x259,
317 0x251,
318 0x248,
319 0x240,
320 0x238,
321 0x230,
322 0x228,
323 0x220,
324 0x218,
325 0x210,
326 0x209,
327 0x201,
328 0x1FA,
329 0x1F2,
330 0x1EB,
331 0x1E4,
332 0x1DD,
333 0x1D6,
334 0x1D0,
335 0x1C9,
336 0x1C2,
337 0x1BC,
338 0x1B6,
339 0x1AF,
340 0x1A9,
341 0x1A3,
342 0x19D,
343 0x197,
344 0x191,
345 0x18C,
346 0x186,
347 0x180,
348 0x17B,
349 0x175,
350 0x170,
351 0x16B,
352 0x165,
353 0x160,
354 0x15B,
355 0x156,
356 0x151,
357 0x14C,
358 0x148,
359 0x143,
360 0x13E,
361 0x13A,
362 0x135,
363 0x131,
364 0x12C,
365 0x128,
366 0x124,
367 0x120,
368 0x11C,
369 0x118,
370 0x114,
371 0x110,
372 0x10C,
373 0x108,
374 0x104,
375 0x100,
376 0xFD,
377 0xF9,
378 0xF5,
379 0xF2,
380 0xEE,
381};
382
diff --git a/quantum/audio/luts.h b/quantum/audio/luts.h
new file mode 100644
index 000000000..7df3078a7
--- /dev/null
+++ b/quantum/audio/luts.h
@@ -0,0 +1,15 @@
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <avr/pgmspace.h>
4
5#ifndef LUTS_H
6#define LUTS_H
7
8#define VIBRATO_LUT_LENGTH 20
9
10#define FREQUENCY_LUT_LENGTH 349
11
12extern const float vibrato_lut[VIBRATO_LUT_LENGTH];
13extern const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH];
14
15#endif /* LUTS_H */ \ No newline at end of file
diff --git a/quantum/audio/musical_notes.h b/quantum/audio/musical_notes.h
new file mode 100644
index 000000000..b08d16a6f
--- /dev/null
+++ b/quantum/audio/musical_notes.h
@@ -0,0 +1,217 @@
1#ifndef MUSICAL_NOTES_H
2#define MUSICAL_NOTES_H
3
4// Tempo Placeholder
5#define TEMPO_DEFAULT 100
6
7
8#define SONG(notes...) { notes }
9
10
11// Note Types
12#define MUSICAL_NOTE(note, duration) {(NOTE##note), duration}
13#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64)
14#define HALF_NOTE(note) MUSICAL_NOTE(note, 32)
15#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16)
16#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8)
17#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4)
18
19#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64+32)
20#define HALF_DOT_NOTE(note) MUSICAL_NOTE(note, 32+16)
21#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16+8)
22#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8+4)
23#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4+2)
24
25// Note Type Shortcuts
26#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration)
27#define W__NOTE(n) WHOLE_NOTE(n)
28#define H__NOTE(n) HALF_NOTE(n)
29#define Q__NOTE(n) QUARTER_NOTE(n)
30#define E__NOTE(n) EIGHTH_NOTE(n)
31#define S__NOTE(n) SIXTEENTH_NOTE(n)
32#define WD_NOTE(n) WHOLE_DOT_NOTE(n)
33#define HD_NOTE(n) HALF_DOT_NOTE(n)
34#define QD_NOTE(n) QUARTER_DOT_NOTE(n)
35#define ED_NOTE(n) EIGHTH_DOT_NOTE(n)
36#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n)
37
38// Note Styles
39// Staccato makes sure there is a rest between each note. Think: TA TA TA
40// Legato makes notes flow together. Think: TAAA
41#define STACCATO 0.01
42#define LEGATO 0
43
44// Note Timbre
45// Changes how the notes sound
46#define TIMBRE_12 0.125
47#define TIMBRE_25 0.250
48#define TIMBRE_50 0.500
49#define TIMBRE_75 0.750
50#define TIMBRE_DEFAULT TIMBRE_50
51
52
53// Notes - # = Octave
54
55#define NOTE_REST 0.00
56
57/* These notes are currently bugged
58#define NOTE_C0 16.35
59#define NOTE_CS0 17.32
60#define NOTE_D0 18.35
61#define NOTE_DS0 19.45
62#define NOTE_E0 20.60
63#define NOTE_F0 21.83
64#define NOTE_FS0 23.12
65#define NOTE_G0 24.50
66#define NOTE_GS0 25.96
67#define NOTE_A0 27.50
68#define NOTE_AS0 29.14
69#define NOTE_B0 30.87
70#define NOTE_C1 32.70
71#define NOTE_CS1 34.65
72#define NOTE_D1 36.71
73#define NOTE_DS1 38.89
74#define NOTE_E1 41.20
75#define NOTE_F1 43.65
76#define NOTE_FS1 46.25
77#define NOTE_G1 49.00
78#define NOTE_GS1 51.91
79#define NOTE_A1 55.00
80#define NOTE_AS1 58.27
81*/
82
83#define NOTE_B1 61.74
84#define NOTE_C2 65.41
85#define NOTE_CS2 69.30
86#define NOTE_D2 73.42
87#define NOTE_DS2 77.78
88#define NOTE_E2 82.41
89#define NOTE_F2 87.31
90#define NOTE_FS2 92.50
91#define NOTE_G2 98.00
92#define NOTE_GS2 103.83
93#define NOTE_A2 110.00
94#define NOTE_AS2 116.54
95#define NOTE_B2 123.47
96#define NOTE_C3 130.81
97#define NOTE_CS3 138.59
98#define NOTE_D3 146.83
99#define NOTE_DS3 155.56
100#define NOTE_E3 164.81
101#define NOTE_F3 174.61
102#define NOTE_FS3 185.00
103#define NOTE_G3 196.00
104#define NOTE_GS3 207.65
105#define NOTE_A3 220.00
106#define NOTE_AS3 233.08
107#define NOTE_B3 246.94
108#define NOTE_C4 261.63
109#define NOTE_CS4 277.18
110#define NOTE_D4 293.66
111#define NOTE_DS4 311.13
112#define NOTE_E4 329.63
113#define NOTE_F4 349.23
114#define NOTE_FS4 369.99
115#define NOTE_G4 392.00
116#define NOTE_GS4 415.30
117#define NOTE_A4 440.00
118#define NOTE_AS4 466.16
119#define NOTE_B4 493.88
120#define NOTE_C5 523.25
121#define NOTE_CS5 554.37
122#define NOTE_D5 587.33
123#define NOTE_DS5 622.25
124#define NOTE_E5 659.26
125#define NOTE_F5 698.46
126#define NOTE_FS5 739.99
127#define NOTE_G5 783.99
128#define NOTE_GS5 830.61
129#define NOTE_A5 880.00
130#define NOTE_AS5 932.33
131#define NOTE_B5 987.77
132#define NOTE_C6 1046.50
133#define NOTE_CS6 1108.73
134#define NOTE_D6 1174.66
135#define NOTE_DS6 1244.51
136#define NOTE_E6 1318.51
137#define NOTE_F6 1396.91
138#define NOTE_FS6 1479.98
139#define NOTE_G6 1567.98
140#define NOTE_GS6 1661.22
141#define NOTE_A6 1760.00
142#define NOTE_AS6 1864.66
143#define NOTE_B6 1975.53
144#define NOTE_C7 2093.00
145#define NOTE_CS7 2217.46
146#define NOTE_D7 2349.32
147#define NOTE_DS7 2489.02
148#define NOTE_E7 2637.02
149#define NOTE_F7 2793.83
150#define NOTE_FS7 2959.96
151#define NOTE_G7 3135.96
152#define NOTE_GS7 3322.44
153#define NOTE_A7 3520.00
154#define NOTE_AS7 3729.31
155#define NOTE_B7 3951.07
156#define NOTE_C8 4186.01
157#define NOTE_CS8 4434.92
158#define NOTE_D8 4698.64
159#define NOTE_DS8 4978.03
160#define NOTE_E8 5274.04
161#define NOTE_F8 5587.65
162#define NOTE_FS8 5919.91
163#define NOTE_G8 6271.93
164#define NOTE_GS8 6644.88
165#define NOTE_A8 7040.00
166#define NOTE_AS8 7458.62
167#define NOTE_B8 7902.13
168
169// Flat Aliases
170#define NOTE_DF0 NOTE_CS0
171#define NOTE_EF0 NOTE_DS0
172#define NOTE_GF0 NOTE_FS0
173#define NOTE_AF0 NOTE_GS0
174#define NOTE_BF0 NOTE_AS0
175#define NOTE_DF1 NOTE_CS1
176#define NOTE_EF1 NOTE_DS1
177#define NOTE_GF1 NOTE_FS1
178#define NOTE_AF1 NOTE_GS1
179#define NOTE_BF1 NOTE_AS1
180#define NOTE_DF2 NOTE_CS2
181#define NOTE_EF2 NOTE_DS2
182#define NOTE_GF2 NOTE_FS2
183#define NOTE_AF2 NOTE_GS2
184#define NOTE_BF2 NOTE_AS2
185#define NOTE_DF3 NOTE_CS3
186#define NOTE_EF3 NOTE_DS3
187#define NOTE_GF3 NOTE_FS3
188#define NOTE_AF3 NOTE_GS3
189#define NOTE_BF3 NOTE_AS3
190#define NOTE_DF4 NOTE_CS4
191#define NOTE_EF4 NOTE_DS4
192#define NOTE_GF4 NOTE_FS4
193#define NOTE_AF4 NOTE_GS4
194#define NOTE_BF4 NOTE_AS4
195#define NOTE_DF5 NOTE_CS5
196#define NOTE_EF5 NOTE_DS5
197#define NOTE_GF5 NOTE_FS5
198#define NOTE_AF5 NOTE_GS5
199#define NOTE_BF5 NOTE_AS5
200#define NOTE_DF6 NOTE_CS6
201#define NOTE_EF6 NOTE_DS6
202#define NOTE_GF6 NOTE_FS6
203#define NOTE_AF6 NOTE_GS6
204#define NOTE_BF6 NOTE_AS6
205#define NOTE_DF7 NOTE_CS7
206#define NOTE_EF7 NOTE_DS7
207#define NOTE_GF7 NOTE_FS7
208#define NOTE_AF7 NOTE_GS7
209#define NOTE_BF7 NOTE_AS7
210#define NOTE_DF8 NOTE_CS8
211#define NOTE_EF8 NOTE_DS8
212#define NOTE_GF8 NOTE_FS8
213#define NOTE_AF8 NOTE_GS8
214#define NOTE_BF8 NOTE_AS8
215
216
217#endif \ No newline at end of file
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h
new file mode 100644
index 000000000..8022ca672
--- /dev/null
+++ b/quantum/audio/song_list.h
@@ -0,0 +1,125 @@
1#include "musical_notes.h"
2
3#ifndef SONG_LIST_H
4#define SONG_LIST_H
5
6#define ODE_TO_JOY \
7 Q__NOTE(_E4), Q__NOTE(_E4), Q__NOTE(_F4), Q__NOTE(_G4), \
8 Q__NOTE(_G4), Q__NOTE(_F4), Q__NOTE(_E4), Q__NOTE(_D4), \
9 Q__NOTE(_C4), Q__NOTE(_C4), Q__NOTE(_D4), Q__NOTE(_E4), \
10 QD_NOTE(_E4), E__NOTE(_D4), H__NOTE(_D4),
11
12#define ROCK_A_BYE_BABY \
13 QD_NOTE(_B4), E__NOTE(_D4), Q__NOTE(_B5), \
14 H__NOTE(_A5), Q__NOTE(_G5), \
15 QD_NOTE(_B4), E__NOTE(_D5), Q__NOTE(_G5), \
16 H__NOTE(_FS5),
17
18#define CLOSE_ENCOUNTERS_5_NOTE \
19 Q__NOTE(_D5), \
20 Q__NOTE(_E5), \
21 Q__NOTE(_C5), \
22 Q__NOTE(_C4), \
23 Q__NOTE(_G4),
24
25#define DOE_A_DEER \
26 QD_NOTE(_C4), E__NOTE(_D4), \
27 QD_NOTE(_E4), E__NOTE(_C4), \
28 Q__NOTE(_E4), Q__NOTE(_C4), \
29 Q__NOTE(_E4),
30
31/* Requires: PLAY_NOTE_ARRAY(..., ..., STACCATO); */
32#define IN_LIKE_FLINT \
33 E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4), \
34 E__NOTE(_AS4), E__NOTE(_B4), QD_NOTE(_CS4), \
35 E__NOTE(_B4), E__NOTE(_CS4), QD_NOTE(_DS4), \
36 E__NOTE(_CS4), E__NOTE(_B4), QD_NOTE(_AS4), \
37 E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4),
38
39#define GOODBYE_SOUND \
40 E__NOTE(_E7), \
41 E__NOTE(_A6), \
42 ED_NOTE(_E6),
43
44#define STARTUP_SOUND \
45 ED_NOTE(_E7 ), \
46 E__NOTE(_CS7), \
47 E__NOTE(_E6 ), \
48 E__NOTE(_A6 ), \
49 M__NOTE(_CS7, 20),
50
51#define QWERTY_SOUND \
52 E__NOTE(_GS6 ), \
53 E__NOTE(_A6 ), \
54 S__NOTE(_REST), \
55 Q__NOTE(_E7 ),
56
57#define COLEMAK_SOUND \
58 E__NOTE(_GS6 ), \
59 E__NOTE(_A6 ), \
60 S__NOTE(_REST), \
61 ED_NOTE(_E7 ), \
62 S__NOTE(_REST), \
63 ED_NOTE(_GS7 ),
64
65#define DVORAK_SOUND \
66 E__NOTE(_GS6 ), \
67 E__NOTE(_A6 ), \
68 S__NOTE(_REST), \
69 E__NOTE(_E7 ), \
70 S__NOTE(_REST), \
71 E__NOTE(_FS7 ), \
72 S__NOTE(_REST), \
73 E__NOTE(_E7 ),
74
75#define PLOVER_SOUND \
76 E__NOTE(_GS6 ), \
77 E__NOTE(_A6 ), \
78 S__NOTE(_REST), \
79 ED_NOTE(_E7 ), \
80 S__NOTE(_REST), \
81 ED_NOTE(_A7 ),
82
83#define PLOVER_GOODBYE_SOUND \
84 E__NOTE(_GS6 ), \
85 E__NOTE(_A6 ), \
86 S__NOTE(_REST), \
87 ED_NOTE(_A7 ), \
88 S__NOTE(_REST), \
89 ED_NOTE(_E7 ),
90
91#define MUSIC_SCALE_SOUND \
92 E__NOTE(_A5 ), \
93 E__NOTE(_B5 ), \
94 E__NOTE(_CS6), \
95 E__NOTE(_D6 ), \
96 E__NOTE(_E6 ), \
97 E__NOTE(_FS6), \
98 E__NOTE(_GS6), \
99 E__NOTE(_A6 ),
100
101#define CAPS_LOCK_ON_SOUND \
102 E__NOTE(_A3), \
103 E__NOTE(_B3),
104
105#define CAPS_LOCK_OFF_SOUND \
106 E__NOTE(_B3), \
107 E__NOTE(_A3),
108
109#define SCROLL_LOCK_ON_SOUND \
110 E__NOTE(_D4), \
111 E__NOTE(_E4),
112
113#define SCROLL_LOCK_OFF_SOUND \
114 E__NOTE(_E4), \
115 E__NOTE(_D4),
116
117#define NUM_LOCK_ON_SOUND \
118 E__NOTE(_D5), \
119 E__NOTE(_E5),
120
121#define NUM_LOCK_OFF_SOUND \
122 E__NOTE(_E5), \
123 E__NOTE(_D5),
124
125#endif
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c
new file mode 100644
index 000000000..6d4172a06
--- /dev/null
+++ b/quantum/audio/voices.c
@@ -0,0 +1,165 @@
1#include "voices.h"
2#include "audio.h"
3#include "stdlib.h"
4
5// these are imported from audio.c
6extern uint16_t envelope_index;
7extern float note_timbre;
8extern float polyphony_rate;
9
10voice_type voice = default_voice;
11
12void set_voice(voice_type v) {
13 voice = v;
14}
15
16void voice_iterate() {
17 voice = (voice + 1) % number_of_voices;
18}
19
20void voice_deiterate() {
21 voice = (voice - 1) % number_of_voices;
22}
23
24float voice_envelope(float frequency) {
25 // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz
26 uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency));
27
28 switch (voice) {
29 case default_voice:
30 note_timbre = TIMBRE_50;
31 polyphony_rate = 0;
32 break;
33
34 case butts_fader:
35 polyphony_rate = 0;
36 switch (compensated_index) {
37 case 0 ... 9:
38 frequency = frequency / 4;
39 note_timbre = TIMBRE_12;
40 break;
41
42 case 10 ... 19:
43 frequency = frequency / 2;
44 note_timbre = TIMBRE_12;
45 break;
46
47 case 20 ... 200:
48 note_timbre = .125 - pow(((float)compensated_index - 20) / (200 - 20), 2)*.125;
49 break;
50
51 default:
52 note_timbre = 0;
53 break;
54 }
55 break;
56
57 // case octave_crunch:
58 // polyphony_rate = 0;
59 // switch (compensated_index) {
60 // case 0 ... 9:
61 // case 20 ... 24:
62 // case 30 ... 32:
63 // frequency = frequency / 2;
64 // note_timbre = TIMBRE_12;
65 // break;
66
67 // case 10 ... 19:
68 // case 25 ... 29:
69 // case 33 ... 35:
70 // frequency = frequency * 2;
71 // note_timbre = TIMBRE_12;
72 // break;
73
74 // default:
75 // note_timbre = TIMBRE_12;
76 // break;
77 // }
78 // break;
79
80 case duty_osc:
81 // This slows the loop down a substantial amount, so higher notes may freeze
82 polyphony_rate = 0;
83 switch (compensated_index) {
84 default:
85 #define OCS_SPEED 10
86 #define OCS_AMP .25
87 // sine wave is slow
88 // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5;
89 // triangle wave is a bit faster
90 note_timbre = (float)abs((compensated_index*OCS_SPEED % 3000) - 1500) * ( OCS_AMP / 1500 ) + (1 - OCS_AMP) / 2;
91 break;
92 }
93 break;
94
95 case duty_octave_down:
96 polyphony_rate = 0;
97 note_timbre = (envelope_index % 2) * .125 + .375 * 2;
98 if ((envelope_index % 4) == 0)
99 note_timbre = 0.5;
100 if ((envelope_index % 8) == 0)
101 note_timbre = 0;
102 break;
103 case delayed_vibrato:
104 polyphony_rate = 0;
105 note_timbre = TIMBRE_50;
106 #define VOICE_VIBRATO_DELAY 150
107 #define VOICE_VIBRATO_SPEED 50
108 switch (compensated_index) {
109 case 0 ... VOICE_VIBRATO_DELAY:
110 break;
111 default:
112 frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)];
113 break;
114 }
115 break;
116 // case delayed_vibrato_octave:
117 // polyphony_rate = 0;
118 // if ((envelope_index % 2) == 1) {
119 // note_timbre = 0.55;
120 // } else {
121 // note_timbre = 0.45;
122 // }
123 // #define VOICE_VIBRATO_DELAY 150
124 // #define VOICE_VIBRATO_SPEED 50
125 // switch (compensated_index) {
126 // case 0 ... VOICE_VIBRATO_DELAY:
127 // break;
128 // default:
129 // frequency = frequency * VIBRATO_LUT[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)];
130 // break;
131 // }
132 // break;
133 // case duty_fifth_down:
134 // note_timbre = 0.5;
135 // if ((envelope_index % 3) == 0)
136 // note_timbre = 0.75;
137 // break;
138 // case duty_fourth_down:
139 // note_timbre = 0.0;
140 // if ((envelope_index % 12) == 0)
141 // note_timbre = 0.75;
142 // if (((envelope_index % 12) % 4) != 1)
143 // note_timbre = 0.75;
144 // break;
145 // case duty_third_down:
146 // note_timbre = 0.5;
147 // if ((envelope_index % 5) == 0)
148 // note_timbre = 0.75;
149 // break;
150 // case duty_fifth_third_down:
151 // note_timbre = 0.5;
152 // if ((envelope_index % 5) == 0)
153 // note_timbre = 0.75;
154 // if ((envelope_index % 3) == 0)
155 // note_timbre = 0.25;
156 // break;
157
158 default:
159 break;
160 }
161
162 return frequency;
163}
164
165
diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h
new file mode 100644
index 000000000..b2495b23b
--- /dev/null
+++ b/quantum/audio/voices.h
@@ -0,0 +1,31 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include <avr/io.h>
4#include <util/delay.h>
5#include "luts.h"
6
7#ifndef VOICES_H
8#define VOICES_H
9
10float voice_envelope(float frequency);
11
12typedef enum {
13 default_voice,
14 butts_fader,
15 octave_crunch,
16 duty_osc,
17 duty_octave_down,
18 delayed_vibrato,
19 // delayed_vibrato_octave,
20 // duty_fifth_down,
21 // duty_fourth_down,
22 // duty_third_down,
23 // duty_fifth_third_down,
24 number_of_voices // important that this is last
25} voice_type;
26
27void set_voice(voice_type v);
28void voice_iterate(void);
29void voice_deiterate(void);
30
31#endif \ No newline at end of file
diff --git a/quantum/wave.h b/quantum/audio/wave.h
index 6ebc34851..6ebc34851 100644
--- a/quantum/wave.h
+++ b/quantum/audio/wave.h
diff --git a/quantum/config_common.h b/quantum/config_common.h
index da53fce89..8ed5f4a10 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -1,70 +1,83 @@
1#ifndef CONFIG_DEFINITIONS_H 1#ifndef CONFIG_DEFINITIONS_H
2#define CONFIG_DEFINITIONS_H 2#define CONFIG_DEFINITIONS_H
3 3
4#define B0 0x20 4/* diode directions */
5#define B1 0x21 5#define COL2ROW 0
6#define B2 0x22 6#define ROW2COL 1
7#define B3 0x23 7/* I/O pins */
8#define B4 0x24 8#define B0 0x30
9#define B5 0x25 9#define B1 0x31
10#define B6 0x26 10#define B2 0x32
11#define B7 0x27 11#define B3 0x33
12#define C0 0x30 12#define B4 0x34
13#define C1 0x31 13#define B5 0x35
14#define C2 0x32 14#define B6 0x36
15#define C3 0x33 15#define B7 0x37
16#define C4 0x34 16#define C0 0x60
17#define C5 0x35 17#define C1 0x61
18#define C6 0x36 18#define C2 0x62
19#define C7 0x37 19#define C3 0x63
20#define D0 0x40 20#define C4 0x64
21#define D1 0x41 21#define C5 0x65
22#define D2 0x42 22#define C6 0x66
23#define D3 0x43 23#define C7 0x67
24#define D4 0x44 24#define D0 0x90
25#define D5 0x45 25#define D1 0x91
26#define D6 0x46 26#define D2 0x92
27#define D7 0x47 27#define D3 0x93
28#define E0 0x50 28#define D4 0x94
29#define E1 0x51 29#define D5 0x95
30#define E2 0x52 30#define D6 0x96
31#define E3 0x53 31#define D7 0x97
32#define E4 0x54 32#define E0 0xC0
33#define E5 0x55 33#define E1 0xC1
34#define E6 0x56 34#define E2 0xC2
35#define E7 0x57 35#define E3 0xC3
36#define F0 0x60 36#define E4 0xC4
37#define F1 0x61 37#define E5 0xC5
38#define F2 0x62 38#define E6 0xC6
39#define F3 0x63 39#define E7 0xC7
40#define F4 0x64 40#define F0 0xF0
41#define F5 0x65 41#define F1 0xF1
42#define F6 0x66 42#define F2 0xF2
43#define F7 0x67 43#define F3 0xF3
44#define F4 0xF4
45#define F5 0xF5
46#define F6 0xF6
47#define F7 0xF7
48#define A0 0x00
49#define A1 0x01
50#define A2 0x02
51#define A3 0x03
52#define A4 0x04
53#define A5 0x05
54#define A6 0x06
55#define A7 0x07
44 56
45#define COL2ROW 0x0
46#define ROW2COL 0x1
47 57
58/* USART configuration */
48#ifdef BLUETOOTH_ENABLE 59#ifdef BLUETOOTH_ENABLE
49#ifdef __AVR_ATmega32U4__ 60# ifdef __AVR_ATmega32U4__
50 #define SERIAL_UART_BAUD 9600 61# define SERIAL_UART_BAUD 9600
51 #define SERIAL_UART_DATA UDR1 62# define SERIAL_UART_DATA UDR1
52 #define SERIAL_UART_UBRR ((F_CPU/(16UL*SERIAL_UART_BAUD))-1) 63# define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1)
53 #define SERIAL_UART_RXD_VECT USART1_RX_vect 64# define SERIAL_UART_RXD_VECT USART1_RX_vect
54 #define SERIAL_UART_TXD_READY (UCSR1A&(1<<UDRE1)) 65# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1))
55 #define SERIAL_UART_INIT() do { \ 66# define SERIAL_UART_INIT() do { \
56 UBRR1L = (uint8_t) SERIAL_UART_UBRR; /* baud rate */ \ 67 /* baud rate */ \
57 UBRR1H = (uint8_t) (SERIAL_UART_UBRR>>8); /* baud rate */ \ 68 UBRR1L = SERIAL_UART_UBRR; \
58 UCSR1B = (1<<TXEN1); /* TX: enable */ \ 69 /* baud rate */ \
59 UCSR1C = (0<<UPM11) | (0<<UPM10) | /* parity: none(00), even(01), odd(11) */ \ 70 UBRR1H = SERIAL_UART_UBRR >> 8; \
60 (0<<UCSZ12) | (1<<UCSZ11) | (1<<UCSZ10); /* data-8bit(011) */ \ 71 /* enable TX */ \
61 sei(); \ 72 UCSR1B = _BV(TXEN1); \
62 } while(0) 73 /* 8-bit data */ \
63#else 74 UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \
64# error "USART configuration is needed." 75 sei(); \
76 } while(0)
77# else
78# error "USART configuration is needed."
65#endif 79#endif
66 80
67
68// I'm fairly sure these aren't needed, but oh well - Jack 81// I'm fairly sure these aren't needed, but oh well - Jack
69 82
70/* 83/*
@@ -113,4 +126,3 @@
113#endif 126#endif
114 127
115#endif 128#endif
116
diff --git a/quantum/dynamic_macro.h b/quantum/dynamic_macro.h
new file mode 100644
index 000000000..e6dbc5b9c
--- /dev/null
+++ b/quantum/dynamic_macro.h
@@ -0,0 +1,231 @@
1/* Author: Wojciech Siewierski < wojciech dot siewierski at onet dot pl > */
2#ifndef DYNAMIC_MACROS_H
3#define DYNAMIC_MACROS_H
4
5#include "action_layer.h"
6
7#ifndef DYNAMIC_MACRO_SIZE
8/* May be overridden with a custom value. Be aware that the effective
9 * macro length is half of this value: each keypress is recorded twice
10 * because of the down-event and up-event. This is not a bug, it's the
11 * intended behavior.
12 *
13 * Usually it should be fine to set the macro size to at least 256 but
14 * there have been reports of it being too much in some users' cases,
15 * so 128 is considered a safe default.
16 */
17#define DYNAMIC_MACRO_SIZE 128
18#endif
19
20/* DYNAMIC_MACRO_RANGE must be set as the last element of user's
21 * "planck_keycodes" enum prior to including this header. This allows
22 * us to 'extend' it.
23 */
24enum dynamic_macro_keycodes {
25 DYN_REC_START1 = DYNAMIC_MACRO_RANGE,
26 DYN_REC_START2,
27 DYN_MACRO_PLAY1,
28 DYN_MACRO_PLAY2,
29};
30
31/* Blink the LEDs to notify the user about some event. */
32void dynamic_macro_led_blink(void)
33{
34 backlight_toggle();
35 _delay_ms(100);
36 backlight_toggle();
37}
38
39/**
40 * Start recording of the dynamic macro.
41 *
42 * @param[out] macro_pointer The new macro buffer iterator.
43 * @param[in] macro_buffer The macro buffer used to initialize macro_pointer.
44 */
45void dynamic_macro_record_start(
46 keyrecord_t **macro_pointer, keyrecord_t *macro_buffer)
47{
48 dynamic_macro_led_blink();
49
50 clear_keyboard();
51 layer_clear();
52 *macro_pointer = macro_buffer;
53}
54
55/**
56 * Play the dynamic macro.
57 *
58 * @param macro_buffer[in] The beginning of the macro buffer being played.
59 * @param macro_end[in] The element after the last macro buffer element.
60 * @param direction[in] Either +1 or -1, which way to iterate the buffer.
61 */
62void dynamic_macro_play(
63 keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction)
64{
65 uint32_t saved_layer_state = layer_state;
66
67 clear_keyboard();
68 layer_clear();
69
70 while (macro_buffer != macro_end) {
71 process_record(macro_buffer);
72 macro_buffer += direction;
73 }
74
75 clear_keyboard();
76
77 layer_state = saved_layer_state;
78}
79
80/**
81 * Record a single key in a dynamic macro.
82 *
83 * @param macro_pointer[in,out] The current buffer position.
84 * @param macro_end2[in] The end of the other macro which shouldn't be overwritten.
85 * @param direction[in] Either +1 or -1, which way to iterate the buffer.
86 * @param record[in] The current keypress.
87 */
88void dynamic_macro_record_key(
89 keyrecord_t **macro_pointer,
90 keyrecord_t *macro_end2,
91 int8_t direction,
92 keyrecord_t *record)
93{
94 if (*macro_pointer + direction != macro_end2) {
95 **macro_pointer = *record;
96 *macro_pointer += direction;
97 } else {
98 /* Notify about the end of buffer. The blinks are paired
99 * because they should happen on both down and up events. */
100 backlight_toggle();
101 }
102}
103
104/**
105 * End recording of the dynamic macro. Essentially just update the
106 * pointer to the end of the macro.
107 */
108void dynamic_macro_record_end(keyrecord_t *macro_pointer, keyrecord_t **macro_end)
109{
110 dynamic_macro_led_blink();
111
112 *macro_end = macro_pointer;
113}
114
115/* Handle the key events related to the dynamic macros. Should be
116 * called from process_record_user() like this:
117 *
118 * bool process_record_user(uint16_t keycode, keyrecord_t *record) {
119 * if (!process_record_dynamic_macro(keycode, record)) {
120 * return false;
121 * }
122 * <...THE REST OF THE FUNCTION...>
123 * }
124 */
125bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record)
126{
127 /* Both macros use the same buffer but read/write on different
128 * ends of it.
129 *
130 * Macro1 is written left-to-right starting from the beginning of
131 * the buffer.
132 *
133 * Macro2 is written right-to-left starting from the end of the
134 * buffer.
135 *
136 * &macro_buffer macro_end
137 * v v
138 * +------------------------------------------------------------+
139 * |>>>>>> MACRO1 >>>>>>| |<<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<|
140 * +------------------------------------------------------------+
141 * ^ ^
142 * r_macro_end r_macro_buffer
143 *
144 * During the recording when one macro encounters the end of the
145 * other macro, the recording is stopped. Apart from this, there
146 * are no arbitrary limits for the macros' length in relation to
147 * each other: for example one can either have two medium sized
148 * macros or one long macro and one short macro. Or even one empty
149 * and one using the whole buffer.
150 */
151 static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE];
152
153 /* Pointer to the first buffer element after the first macro.
154 * Initially points to the very beginning of the buffer since the
155 * macro is empty. */
156 static keyrecord_t *macro_end = macro_buffer;
157
158 /* The other end of the macro buffer. Serves as the beginning of
159 * the second macro. */
160 static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1;
161
162 /* Like macro_end but for the second macro. */
163 static keyrecord_t *r_macro_end = r_macro_buffer;
164
165 /* A persistent pointer to the current macro position (iterator)
166 * used during the recording. */
167 static keyrecord_t *macro_pointer = NULL;
168
169 /* 0 - no macro is being recorded right now
170 * 1,2 - either macro 1 or 2 is being recorded */
171 static uint8_t macro_id = 0;
172
173 if (macro_id == 0) {
174 /* No macro recording in progress. */
175 if (!record->event.pressed) {
176 switch (keycode) {
177 case DYN_REC_START1:
178 dynamic_macro_record_start(&macro_pointer, macro_buffer);
179 macro_id = 1;
180 return false;
181 case DYN_REC_START2:
182 dynamic_macro_record_start(&macro_pointer, r_macro_buffer);
183 macro_id = 2;
184 return false;
185 case DYN_MACRO_PLAY1:
186 dynamic_macro_play(macro_buffer, macro_end, +1);
187 return false;
188 case DYN_MACRO_PLAY2:
189 dynamic_macro_play(r_macro_buffer, r_macro_end, -1);
190 return false;
191 }
192 }
193 } else {
194 /* A macro is being recorded right now. */
195 switch (keycode) {
196 case MO(_DYN):
197 /* Use the layer key used to access the macro recording as
198 * a stop button. */
199 if (record->event.pressed) { /* Ignore the initial release
200 * just after the recoding
201 * starts. */
202 switch (macro_id) {
203 case 1:
204 dynamic_macro_record_end(macro_pointer, &macro_end);
205 break;
206 case 2:
207 dynamic_macro_record_end(macro_pointer, &r_macro_end);
208 break;
209 }
210 macro_id = 0;
211 }
212 return false;
213 default:
214 /* Store the key in the macro buffer and process it normally. */
215 switch (macro_id) {
216 case 1:
217 dynamic_macro_record_key(&macro_pointer, r_macro_end, +1, record);
218 break;
219 case 2:
220 dynamic_macro_record_key(&macro_pointer, macro_end, -1, record);
221 break;
222 }
223 return true;
224 break;
225 }
226 }
227
228 return true;
229}
230
231#endif
diff --git a/quantum/keycode_config.c b/quantum/keycode_config.c
new file mode 100644
index 000000000..6d90781a1
--- /dev/null
+++ b/quantum/keycode_config.c
@@ -0,0 +1,74 @@
1#include "keycode_config.h"
2
3extern keymap_config_t keymap_config;
4
5uint16_t keycode_config(uint16_t keycode) {
6
7 switch (keycode) {
8 case KC_CAPSLOCK:
9 case KC_LOCKING_CAPS:
10 if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) {
11 return KC_LCTL;
12 }
13 return keycode;
14 case KC_LCTL:
15 if (keymap_config.swap_control_capslock) {
16 return KC_CAPSLOCK;
17 }
18 return KC_LCTL;
19 case KC_LALT:
20 if (keymap_config.swap_lalt_lgui) {
21 if (keymap_config.no_gui) {
22 return KC_NO;
23 }
24 return KC_LGUI;
25 }
26 return KC_LALT;
27 case KC_LGUI:
28 if (keymap_config.swap_lalt_lgui) {
29 return KC_LALT;
30 }
31 if (keymap_config.no_gui) {
32 return KC_NO;
33 }
34 return KC_LGUI;
35 case KC_RALT:
36 if (keymap_config.swap_ralt_rgui) {
37 if (keymap_config.no_gui) {
38 return KC_NO;
39 }
40 return KC_RGUI;
41 }
42 return KC_RALT;
43 case KC_RGUI:
44 if (keymap_config.swap_ralt_rgui) {
45 return KC_RALT;
46 }
47 if (keymap_config.no_gui) {
48 return KC_NO;
49 }
50 return KC_RGUI;
51 case KC_GRAVE:
52 if (keymap_config.swap_grave_esc) {
53 return KC_ESC;
54 }
55 return KC_GRAVE;
56 case KC_ESC:
57 if (keymap_config.swap_grave_esc) {
58 return KC_GRAVE;
59 }
60 return KC_ESC;
61 case KC_BSLASH:
62 if (keymap_config.swap_backslash_backspace) {
63 return KC_BSPACE;
64 }
65 return KC_BSLASH;
66 case KC_BSPACE:
67 if (keymap_config.swap_backslash_backspace) {
68 return KC_BSLASH;
69 }
70 return KC_BSPACE;
71 default:
72 return keycode;
73 }
74} \ No newline at end of file
diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h
new file mode 100644
index 000000000..c15b0d32f
--- /dev/null
+++ b/quantum/keycode_config.h
@@ -0,0 +1,26 @@
1#include "eeconfig.h"
2#include "keycode.h"
3
4#ifndef KEYCODE_CONFIG_H
5#define KEYCODE_CONFIG_H
6
7uint16_t keycode_config(uint16_t keycode);
8
9/* NOTE: Not portable. Bit field order depends on implementation */
10typedef union {
11 uint16_t raw;
12 struct {
13 bool swap_control_capslock:1;
14 bool capslock_to_control:1;
15 bool swap_lalt_lgui:1;
16 bool swap_ralt_rgui:1;
17 bool no_gui:1;
18 bool swap_grave_esc:1;
19 bool swap_backslash_backspace:1;
20 bool nkro:1;
21 };
22} keymap_config_t;
23
24extern keymap_config_t keymap_config;
25
26#endif /* KEYCODE_CONFIG_H */
diff --git a/quantum/keymap.h b/quantum/keymap.h
new file mode 100644
index 000000000..a01bbfbd1
--- /dev/null
+++ b/quantum/keymap.h
@@ -0,0 +1,350 @@
1/*
2Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef KEYMAP_H
19#define KEYMAP_H
20
21#include <stdint.h>
22#include <stdbool.h>
23#include "action.h"
24#if defined(__AVR__)
25#include <avr/pgmspace.h>
26#endif
27#include "keycode.h"
28#include "action_macro.h"
29#include "report.h"
30#include "host.h"
31// #include "print.h"
32#include "debug.h"
33#include "keycode_config.h"
34
35// ChibiOS uses RESET in its FlagStatus enumeration
36// Therefore define it as QK_RESET here, to avoid name collision
37#if defined(PROTOCOL_CHIBIOS)
38#define RESET QK_RESET
39#endif
40
41/* translates key to keycode */
42uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key);
43
44extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
45extern const uint16_t fn_actions[];
46
47enum quantum_keycodes {
48 // Ranges used in shortucuts - not to be used directly
49 QK_TMK = 0x0000,
50 QK_TMK_MAX = 0x00FF,
51 QK_MODS = 0x0100,
52 QK_LCTL = 0x0100,
53 QK_LSFT = 0x0200,
54 QK_LALT = 0x0400,
55 QK_LGUI = 0x0800,
56 QK_RCTL = 0x1100,
57 QK_RSFT = 0x1200,
58 QK_RALT = 0x1400,
59 QK_RGUI = 0x1800,
60 QK_MODS_MAX = 0x1FFF,
61 QK_FUNCTION = 0x2000,
62 QK_FUNCTION_MAX = 0x2FFF,
63 QK_MACRO = 0x3000,
64 QK_MACRO_MAX = 0x3FFF,
65 QK_LAYER_TAP = 0x4000,
66 QK_LAYER_TAP_MAX = 0x4FFF,
67 QK_TO = 0x5000,
68 QK_TO_MAX = 0x50FF,
69 QK_MOMENTARY = 0x5100,
70 QK_MOMENTARY_MAX = 0x51FF,
71 QK_DEF_LAYER = 0x5200,
72 QK_DEF_LAYER_MAX = 0x52FF,
73 QK_TOGGLE_LAYER = 0x5300,
74 QK_TOGGLE_LAYER_MAX = 0x53FF,
75 QK_ONE_SHOT_LAYER = 0x5400,
76 QK_ONE_SHOT_LAYER_MAX = 0x54FF,
77 QK_ONE_SHOT_MOD = 0x5500,
78 QK_ONE_SHOT_MOD_MAX = 0x55FF,
79#ifndef DISABLE_CHORDING
80 QK_CHORDING = 0x5600,
81 QK_CHORDING_MAX = 0x56FF,
82#endif
83 QK_MOD_TAP = 0x6000,
84 QK_MOD_TAP_MAX = 0x6FFF,
85 QK_TAP_DANCE = 0x7100,
86 QK_TAP_DANCE_MAX = 0x71FF,
87#ifdef UNICODEMAP_ENABLE
88 QK_UNICODE_MAP = 0x7800,
89 QK_UNICODE_MAP_MAX = 0x7FFF,
90#endif
91#ifdef UNICODE_ENABLE
92 QK_UNICODE = 0x8000,
93 QK_UNICODE_MAX = 0xFFFF,
94#endif
95
96 // Loose keycodes - to be used directly
97
98 RESET = 0x7000,
99 DEBUG,
100 MAGIC_SWAP_CONTROL_CAPSLOCK,
101 MAGIC_CAPSLOCK_TO_CONTROL,
102 MAGIC_SWAP_LALT_LGUI,
103 MAGIC_SWAP_RALT_RGUI,
104 MAGIC_NO_GUI,
105 MAGIC_SWAP_GRAVE_ESC,
106 MAGIC_SWAP_BACKSLASH_BACKSPACE,
107 MAGIC_HOST_NKRO,
108 MAGIC_SWAP_ALT_GUI,
109 MAGIC_UNSWAP_CONTROL_CAPSLOCK,
110 MAGIC_UNCAPSLOCK_TO_CONTROL,
111 MAGIC_UNSWAP_LALT_LGUI,
112 MAGIC_UNSWAP_RALT_RGUI,
113 MAGIC_UNNO_GUI,
114 MAGIC_UNSWAP_GRAVE_ESC,
115 MAGIC_UNSWAP_BACKSLASH_BACKSPACE,
116 MAGIC_UNHOST_NKRO,
117 MAGIC_UNSWAP_ALT_GUI,
118 MAGIC_TOGGLE_NKRO,
119
120 // Leader key
121#ifndef DISABLE_LEADER
122 KC_LEAD,
123#endif
124
125 // Audio on/off/toggle
126 AU_ON,
127 AU_OFF,
128 AU_TOG,
129
130 // Music mode on/off/toggle
131 MU_ON,
132 MU_OFF,
133 MU_TOG,
134
135 // Music voice iterate
136 MUV_IN,
137 MUV_DE,
138
139 // Midi mode on/off
140 MIDI_ON,
141 MIDI_OFF,
142
143 // Backlight functionality
144 BL_0,
145 BL_1,
146 BL_2,
147 BL_3,
148 BL_4,
149 BL_5,
150 BL_6,
151 BL_7,
152 BL_8,
153 BL_9,
154 BL_10,
155 BL_11,
156 BL_12,
157 BL_13,
158 BL_14,
159 BL_15,
160 BL_DEC,
161 BL_INC,
162 BL_TOGG,
163 BL_STEP,
164
165 // RGB functionality
166 RGB_TOG,
167 RGB_MOD,
168 RGB_HUI,
169 RGB_HUD,
170 RGB_SAI,
171 RGB_SAD,
172 RGB_VAI,
173 RGB_VAD,
174
175 // Left shift, open paren
176 KC_LSPO,
177
178 // Right shift, close paren
179 KC_RSPC,
180
181 // always leave at the end
182 SAFE_RANGE
183};
184
185// Ability to use mods in layouts
186#define LCTL(kc) (kc | QK_LCTL)
187#define LSFT(kc) (kc | QK_LSFT)
188#define LALT(kc) (kc | QK_LALT)
189#define LGUI(kc) (kc | QK_LGUI)
190#define RCTL(kc) (kc | QK_RCTL)
191#define RSFT(kc) (kc | QK_RSFT)
192#define RALT(kc) (kc | QK_RALT)
193#define RGUI(kc) (kc | QK_RGUI)
194
195#define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI)
196#define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT)
197#define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI)
198#define ALTG(kc) (kc | QK_RCTL | QK_RALT)
199
200#define MOD_HYPR 0xf
201#define MOD_MEH 0x7
202
203
204// Aliases for shifted symbols
205// Each key has a 4-letter code, and some have longer aliases too.
206// While the long aliases are descriptive, the 4-letter codes
207// make for nicer grid layouts (everything lines up), and are
208// the preferred style for Quantum.
209#define KC_TILD LSFT(KC_GRV) // ~
210#define KC_TILDE KC_TILD
211
212#define KC_EXLM LSFT(KC_1) // !
213#define KC_EXCLAIM KC_EXLM
214
215#define KC_AT LSFT(KC_2) // @
216
217#define KC_HASH LSFT(KC_3) // #
218
219#define KC_DLR LSFT(KC_4) // $
220#define KC_DOLLAR KC_DLR
221
222#define KC_PERC LSFT(KC_5) // %
223#define KC_PERCENT KC_PERC
224
225#define KC_CIRC LSFT(KC_6) // ^
226#define KC_CIRCUMFLEX KC_CIRC
227
228#define KC_AMPR LSFT(KC_7) // &
229#define KC_AMPERSAND KC_AMPR
230
231#define KC_ASTR LSFT(KC_8) // *
232#define KC_ASTERISK KC_ASTR
233
234#define KC_LPRN LSFT(KC_9) // (
235#define KC_LEFT_PAREN KC_LPRN
236
237#define KC_RPRN LSFT(KC_0) // )
238#define KC_RIGHT_PAREN KC_RPRN
239
240#define KC_UNDS LSFT(KC_MINS) // _
241#define KC_UNDERSCORE KC_UNDS
242
243#define KC_PLUS LSFT(KC_EQL) // +
244
245#define KC_LCBR LSFT(KC_LBRC) // {
246#define KC_LEFT_CURLY_BRACE KC_LCBR
247
248#define KC_RCBR LSFT(KC_RBRC) // }
249#define KC_RIGHT_CURLY_BRACE KC_RCBR
250
251#define KC_LABK LSFT(KC_COMM) // <
252#define KC_LEFT_ANGLE_BRACKET KC_LABK
253
254#define KC_RABK LSFT(KC_DOT) // >
255#define KC_RIGHT_ANGLE_BRACKET KC_RABK
256
257#define KC_COLN LSFT(KC_SCLN) // :
258#define KC_COLON KC_COLN
259
260#define KC_PIPE LSFT(KC_BSLS) // |
261
262#define KC_LT LSFT(KC_COMM) // <
263
264#define KC_GT LSFT(KC_DOT) // >
265
266#define KC_QUES LSFT(KC_SLSH) // ?
267#define KC_QUESTION KC_QUES
268
269#define KC_DQT LSFT(KC_QUOT) // "
270#define KC_DOUBLE_QUOTE KC_DQT
271#define KC_DQUO KC_DQT
272
273#define KC_DELT KC_DELETE // Del key (four letter code)
274
275// Alias for function layers than expand past FN31
276#define FUNC(kc) (kc | QK_FUNCTION)
277
278// Aliases
279#define S(kc) LSFT(kc)
280#define F(kc) FUNC(kc)
281
282#define M(kc) (kc | QK_MACRO)
283
284#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)
285
286// L-ayer, T-ap - 256 keycode max, 16 layer max
287#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
288
289#define AG_SWAP MAGIC_SWAP_ALT_GUI
290#define AG_NORM MAGIC_UNSWAP_ALT_GUI
291
292#define BL_ON BL_9
293#define BL_OFF BL_0
294
295#define MI_ON MIDI_ON
296#define MI_OFF MIDI_OFF
297
298// GOTO layer - 16 layers max
299// when:
300// ON_PRESS = 1
301// ON_RELEASE = 2
302// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default.
303// In fact, we changed it to assume ON_PRESS for sanity/simplicity. If needed, you can add your own
304// keycode modeled after the old version, kept below for this.
305/* #define TO(layer, when) (layer | QK_TO | (when << 0x4)) */
306#define TO(layer) (layer | QK_TO | (ON_PRESS << 0x4))
307
308// Momentary switch layer - 256 layer max
309#define MO(layer) (layer | QK_MOMENTARY)
310
311// Set default layer - 256 layer max
312#define DF(layer) (layer | QK_DEF_LAYER)
313
314// Toggle to layer - 256 layer max
315#define TG(layer) (layer | QK_TOGGLE_LAYER)
316
317// One-shot layer - 256 layer max
318#define OSL(layer) (layer | QK_ONE_SHOT_LAYER)
319
320// One-shot mod
321#define OSM(mod) (mod | QK_ONE_SHOT_MOD)
322
323// M-od, T-ap - 256 keycode max
324#define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8))
325#define CTL_T(kc) MT(MOD_LCTL, kc)
326#define SFT_T(kc) MT(MOD_LSFT, kc)
327#define ALT_T(kc) MT(MOD_LALT, kc)
328#define GUI_T(kc) MT(MOD_LGUI, kc)
329#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal
330#define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl
331#define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui
332#define ALL_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI), kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
333
334// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap
335#define KC_HYPR HYPR(KC_NO)
336#define KC_MEH MEH(KC_NO)
337
338#ifdef UNICODE_ENABLE
339 // For sending unicode codes.
340 // You may not send codes over 7FFF -- this supports most of UTF8.
341 // To have a key that sends out Œ, go UC(0x0152)
342 #define UNICODE(n) (n | QK_UNICODE)
343 #define UC(n) UNICODE(n)
344#endif
345
346#ifdef UNICODEMAP_ENABLE
347 #define X(n) (n | QK_UNICODE_MAP)
348#endif
349
350#endif
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
index ae109da16..833e5a8f8 100644
--- a/quantum/keymap_common.c
+++ b/quantum/keymap_common.c
@@ -15,236 +15,46 @@ You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>. 15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/ 16*/
17 17
18#include "keymap_common.h" 18#include "keymap.h"
19#include "report.h" 19#include "report.h"
20#include "keycode.h" 20#include "keycode.h"
21#include "action_layer.h" 21#include "action_layer.h"
22#if defined(__AVR__)
22#include <util/delay.h> 23#include <util/delay.h>
24#include <stdio.h>
25#endif
23#include "action.h" 26#include "action.h"
24#include "action_macro.h" 27#include "action_macro.h"
25#include "debug.h" 28#include "debug.h"
26#include "backlight.h" 29#include "backlight.h"
27#include "keymap_midi.h" 30#include "quantum.h"
28
29#include <stdio.h>
30#include <inttypes.h>
31#ifdef AUDIO_ENABLE
32 #include "audio.h"
33 31
34 float goodbye[][2] = { 32#ifdef MIDI_ENABLE
35 {440.0*pow(2.0,(67)/12.0), 400}, 33 #include "process_midi.h"
36 {0, 50},
37 {440.0*pow(2.0,(60)/12.0), 400},
38 {0, 50},
39 {440.0*pow(2.0,(55)/12.0), 600},
40 };
41#endif 34#endif
42 35
43static action_t keycode_to_action(uint16_t keycode); 36extern keymap_config_t keymap_config;
37
38#include <inttypes.h>
44 39
45/* converts key to action */ 40/* converts key to action */
46action_t action_for_key(uint8_t layer, keypos_t key) 41action_t action_for_key(uint8_t layer, keypos_t key)
47{ 42{
48 // 16bit keycodes - important 43 // 16bit keycodes - important
49 uint16_t keycode = keymap_key_to_keycode(layer, key); 44 uint16_t keycode = keymap_key_to_keycode(layer, key);
50 45
51 if (keycode >= 0x0100 && keycode < 0x2000) { 46 // keycode remapping
52 // Has a modifier 47 keycode = keycode_config(keycode);
53 action_t action;
54 // Split it up
55 action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key
56 return action;
57 } else if (keycode >= 0x2000 && keycode < 0x3000) {
58 // Is a shortcut for function layer, pull last 12bits
59 // This means we have 4,096 FN macros at our disposal
60 return keymap_func_to_action(keycode & 0xFFF);
61 } else if (keycode >= 0x3000 && keycode < 0x4000) {
62 // When the code starts with 3, it's an action macro.
63 action_t action;
64 action.code = ACTION_MACRO(keycode & 0xFF);
65 return action;
66#ifdef BACKLIGHT_ENABLE
67 } else if (keycode >= BL_0 && keycode <= BL_15) {
68 action_t action;
69 action.code = ACTION_BACKLIGHT_LEVEL(keycode & 0x000F);
70 return action;
71 } else if (keycode == BL_DEC) {
72 action_t action;
73 action.code = ACTION_BACKLIGHT_DECREASE();
74 return action;
75 } else if (keycode == BL_INC) {
76 action_t action;
77 action.code = ACTION_BACKLIGHT_INCREASE();
78 return action;
79 } else if (keycode == BL_TOGG) {
80 action_t action;
81 action.code = ACTION_BACKLIGHT_TOGGLE();
82 return action;
83 } else if (keycode == BL_STEP) {
84 action_t action;
85 action.code = ACTION_BACKLIGHT_STEP();
86 return action;
87#endif
88 } else if (keycode == RESET) { // RESET is 0x5000, which is why this is here
89 clear_keyboard();
90 #ifdef AUDIO_ENABLE
91 play_notes(&goodbye, 5, false);
92 #endif
93 _delay_ms(250);
94 bootloader_jump();
95 return;
96 } else if (keycode == DEBUG) { // DEBUG is 0x5001
97 // TODO: Does this actually work?
98 print("\nDEBUG: enabled.\n");
99 debug_enable = true;
100 return;
101 } else if (keycode >= 0x5000 && keycode < 0x6000) {
102 // Layer movement shortcuts
103 // See .h to see constraints/usage
104 int type = (keycode >> 0x8) & 0xF;
105 if (type == 0x1) {
106 // Layer set "GOTO"
107 int when = (keycode >> 0x4) & 0x3;
108 int layer = keycode & 0xF;
109 action_t action;
110 action.code = ACTION_LAYER_SET(layer, when);
111 return action;
112 } else if (type == 0x2) {
113 // Momentary layer
114 int layer = keycode & 0xFF;
115 action_t action;
116 action.code = ACTION_LAYER_MOMENTARY(layer);
117 return action;
118 } else if (type == 0x3) {
119 // Set default layer
120 int layer = keycode & 0xFF;
121 action_t action;
122 action.code = ACTION_DEFAULT_LAYER_SET(layer);
123 return action;
124 } else if (type == 0x4) {
125 // Set default layer
126 int layer = keycode & 0xFF;
127 action_t action;
128 action.code = ACTION_LAYER_TOGGLE(layer);
129 return action;
130 }
131#ifdef MIDI_ENABLE
132 } else if (keycode >= 0x6000 && keycode < 0x7000) {
133 action_t action;
134 action.code = ACTION_FUNCTION_OPT(keycode & 0xFF, (keycode & 0x0F00) >> 8);
135 return action;
136#endif
137 } else if (keycode >= 0x7000 && keycode < 0x8000) {
138 action_t action;
139 action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
140 return action;
141 } else if (keycode >= 0x8000 && keycode < 0x9000) {
142 action_t action;
143 action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
144 return action;
145#ifdef UNICODE_ENABLE
146 } else if (keycode >= 0x8000000) {
147 action_t action;
148 uint16_t unicode = keycode & ~(0x8000);
149 action.code = ACTION_FUNCTION_OPT(unicode & 0xFF, (unicode & 0xFF00) >> 8);
150 return action;
151#endif
152 } else {
153 48
154 } 49 action_t action;
50 uint8_t action_layer, when, mod;
51 // The arm-none-eabi compiler generates out of bounds warnings when using the fn_actions directly for some reason
52 const uint16_t* actions = fn_actions;
155 53
156 switch (keycode) { 54 switch (keycode) {
157 case KC_FN0 ... KC_FN31: 55 case KC_FN0 ... KC_FN31:
158 return keymap_fn_to_action(keycode); 56 action.code = pgm_read_word(&actions[FN_INDEX(keycode)]);
159#ifdef BOOTMAGIC_ENABLE 57 break;
160 case KC_CAPSLOCK:
161 case KC_LOCKING_CAPS:
162 if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) {
163 return keycode_to_action(KC_LCTL);
164 }
165 return keycode_to_action(keycode);
166 case KC_LCTL:
167 if (keymap_config.swap_control_capslock) {
168 return keycode_to_action(KC_CAPSLOCK);
169 }
170 return keycode_to_action(KC_LCTL);
171 case KC_LALT:
172 if (keymap_config.swap_lalt_lgui) {
173 if (keymap_config.no_gui) {
174 return keycode_to_action(ACTION_NO);
175 }
176 return keycode_to_action(KC_LGUI);
177 }
178 return keycode_to_action(KC_LALT);
179 case KC_LGUI:
180 if (keymap_config.swap_lalt_lgui) {
181 return keycode_to_action(KC_LALT);
182 }
183 if (keymap_config.no_gui) {
184 return keycode_to_action(ACTION_NO);
185 }
186 return keycode_to_action(KC_LGUI);
187 case KC_RALT:
188 if (keymap_config.swap_ralt_rgui) {
189 if (keymap_config.no_gui) {
190 return keycode_to_action(ACTION_NO);
191 }
192 return keycode_to_action(KC_RGUI);
193 }
194 return keycode_to_action(KC_RALT);
195 case KC_RGUI:
196 if (keymap_config.swap_ralt_rgui) {
197 return keycode_to_action(KC_RALT);
198 }
199 if (keymap_config.no_gui) {
200 return keycode_to_action(ACTION_NO);
201 }
202 return keycode_to_action(KC_RGUI);
203 case KC_GRAVE:
204 if (keymap_config.swap_grave_esc) {
205 return keycode_to_action(KC_ESC);
206 }
207 return keycode_to_action(KC_GRAVE);
208 case KC_ESC:
209 if (keymap_config.swap_grave_esc) {
210 return keycode_to_action(KC_GRAVE);
211 }
212 return keycode_to_action(KC_ESC);
213 case KC_BSLASH:
214 if (keymap_config.swap_backslash_backspace) {
215 return keycode_to_action(KC_BSPACE);
216 }
217 return keycode_to_action(KC_BSLASH);
218 case KC_BSPACE:
219 if (keymap_config.swap_backslash_backspace) {
220 return keycode_to_action(KC_BSLASH);
221 }
222 return keycode_to_action(KC_BSPACE);
223#endif
224 default:
225 return keycode_to_action(keycode);
226 }
227}
228
229
230/* Macro */
231__attribute__ ((weak))
232const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
233{
234 return MACRO_NONE;
235}
236
237/* Function */
238__attribute__ ((weak))
239void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
240{
241}
242
243/* translates keycode to action */
244static action_t keycode_to_action(uint16_t keycode)
245{
246 action_t action;
247 switch (keycode) {
248 case KC_A ... KC_EXSEL: 58 case KC_A ... KC_EXSEL:
249 case KC_LCTRL ... KC_RGUI: 59 case KC_LCTRL ... KC_RGUI:
250 action.code = ACTION_KEY(keycode); 60 action.code = ACTION_KEY(keycode);
@@ -252,7 +62,7 @@ static action_t keycode_to_action(uint16_t keycode)
252 case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE: 62 case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
253 action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode)); 63 action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
254 break; 64 break;
255 case KC_AUDIO_MUTE ... KC_WWW_FAVORITES: 65 case KC_AUDIO_MUTE ... KC_MEDIA_REWIND:
256 action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode)); 66 action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
257 break; 67 break;
258 case KC_MS_UP ... KC_MS_ACCEL2: 68 case KC_MS_UP ... KC_MS_ACCEL2:
@@ -261,6 +71,73 @@ static action_t keycode_to_action(uint16_t keycode)
261 case KC_TRNS: 71 case KC_TRNS:
262 action.code = ACTION_TRANSPARENT; 72 action.code = ACTION_TRANSPARENT;
263 break; 73 break;
74 case QK_MODS ... QK_MODS_MAX: ;
75 // Has a modifier
76 // Split it up
77 action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key
78 break;
79 case QK_FUNCTION ... QK_FUNCTION_MAX: ;
80 // Is a shortcut for function action_layer, pull last 12bits
81 // This means we have 4,096 FN macros at our disposal
82 action.code = pgm_read_word(&actions[(int)keycode & 0xFFF]);
83 break;
84 case QK_MACRO ... QK_MACRO_MAX:
85 action.code = ACTION_MACRO(keycode & 0xFF);
86 break;
87 case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
88 action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
89 break;
90 case QK_TO ... QK_TO_MAX: ;
91 // Layer set "GOTO"
92 when = (keycode >> 0x4) & 0x3;
93 action_layer = keycode & 0xF;
94 action.code = ACTION_LAYER_SET(action_layer, when);
95 break;
96 case QK_MOMENTARY ... QK_MOMENTARY_MAX: ;
97 // Momentary action_layer
98 action_layer = keycode & 0xFF;
99 action.code = ACTION_LAYER_MOMENTARY(action_layer);
100 break;
101 case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: ;
102 // Set default action_layer
103 action_layer = keycode & 0xFF;
104 action.code = ACTION_DEFAULT_LAYER_SET(action_layer);
105 break;
106 case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: ;
107 // Set toggle
108 action_layer = keycode & 0xFF;
109 action.code = ACTION_LAYER_TOGGLE(action_layer);
110 break;
111 case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: ;
112 // OSL(action_layer) - One-shot action_layer
113 action_layer = keycode & 0xFF;
114 action.code = ACTION_LAYER_ONESHOT(action_layer);
115 break;
116 case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: ;
117 // OSM(mod) - One-shot mod
118 mod = keycode & 0xFF;
119 action.code = ACTION_MODS_ONESHOT(mod);
120 break;
121 case QK_MOD_TAP ... QK_MOD_TAP_MAX:
122 action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
123 break;
124 #ifdef BACKLIGHT_ENABLE
125 case BL_0 ... BL_15:
126 action.code = ACTION_BACKLIGHT_LEVEL(keycode - BL_0);
127 break;
128 case BL_DEC:
129 action.code = ACTION_BACKLIGHT_DECREASE();
130 break;
131 case BL_INC:
132 action.code = ACTION_BACKLIGHT_INCREASE();
133 break;
134 case BL_TOGG:
135 action.code = ACTION_BACKLIGHT_TOGGLE();
136 break;
137 case BL_STEP:
138 action.code = ACTION_BACKLIGHT_STEP();
139 break;
140 #endif
264 default: 141 default:
265 action.code = ACTION_NO; 142 action.code = ACTION_NO;
266 break; 143 break;
@@ -268,22 +145,27 @@ static action_t keycode_to_action(uint16_t keycode)
268 return action; 145 return action;
269} 146}
270 147
148__attribute__ ((weak))
149const uint16_t PROGMEM fn_actions[] = {
271 150
272/* translates key to keycode */ 151};
273uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) 152
153/* Macro */
154__attribute__ ((weak))
155const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
274{ 156{
275 // Read entire word (16bits) 157 return MACRO_NONE;
276 return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
277} 158}
278 159
279/* translates Fn keycode to action */ 160/* Function */
280action_t keymap_fn_to_action(uint16_t keycode) 161__attribute__ ((weak))
162void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
281{ 163{
282 return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) };
283} 164}
284 165
285action_t keymap_func_to_action(uint16_t keycode) 166/* translates key to keycode */
167uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
286{ 168{
287 // For FUNC without 8bit limit 169 // Read entire word (16bits)
288 return (action_t){ .code = pgm_read_word(&fn_actions[(int)keycode]) }; 170 return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
289} 171}
diff --git a/quantum/keymap_common.h b/quantum/keymap_common.h
deleted file mode 100644
index 3db40772e..000000000
--- a/quantum/keymap_common.h
+++ /dev/null
@@ -1,214 +0,0 @@
1/*
2Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef KEYMAP_H
19#define KEYMAP_H
20
21#include <stdint.h>
22#include <stdbool.h>
23#include "action.h"
24#include <avr/pgmspace.h>
25#include "keycode.h"
26#include "keymap.h"
27#include "action_macro.h"
28#include "report.h"
29#include "host.h"
30// #include "print.h"
31#include "debug.h"
32
33#ifdef BOOTMAGIC_ENABLE
34/* NOTE: Not portable. Bit field order depends on implementation */
35typedef union {
36 uint16_t raw;
37 struct {
38 bool swap_control_capslock:1;
39 bool capslock_to_control:1;
40 bool swap_lalt_lgui:1;
41 bool swap_ralt_rgui:1;
42 bool no_gui:1;
43 bool swap_grave_esc:1;
44 bool swap_backslash_backspace:1;
45 bool nkro:1;
46 };
47} keymap_config_t;
48keymap_config_t keymap_config;
49#endif
50
51
52/* translates key to keycode */
53uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key);
54
55/* translates Fn keycode to action */
56action_t keymap_fn_to_action(uint16_t keycode);
57
58/* translates Fn keycode to action */
59action_t keymap_func_to_action(uint16_t keycode);
60
61extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
62extern const uint16_t fn_actions[];
63
64// Ability to use mods in layouts
65#define LCTL(kc) kc | 0x0100
66#define LSFT(kc) kc | 0x0200
67#define LALT(kc) kc | 0x0400
68#define LGUI(kc) kc | 0x0800
69#define HYPR(kc) kc | 0x0F00
70#define MEH(kc) kc | 0x0700
71#define LCAG(kc) kc | 0x0D00 // Modifier Ctrl Alt and GUI
72
73#define RCTL(kc) kc | 0x1100
74#define RSFT(kc) kc | 0x1200
75#define RALT(kc) kc | 0x1400
76#define RGUI(kc) kc | 0x1800
77
78// Aliases for shifted symbols
79// Each key has a 4-letter code, and some have longer aliases too.
80// While the long aliases are descriptive, the 4-letter codes
81// make for nicer grid layouts (everything lines up), and are
82// the preferred style for Quantum.
83#define KC_TILD LSFT(KC_GRV) // ~
84#define KC_TILDE KC_TILD
85
86#define KC_EXLM LSFT(KC_1) // !
87#define KC_EXCLAIM KC_EXLM
88
89#define KC_AT LSFT(KC_2) // @
90#define KC_HASH LSFT(KC_3) // #
91
92#define KC_DLR LSFT(KC_4) // $
93#define KC_DOLLAR KC_DLR
94
95#define KC_PERC LSFT(KC_5) // %
96#define KC_PERCENT KC_PERC
97
98#define KC_CIRC LSFT(KC_6) // ^
99#define KC_CIRCUMFLEX KC_CIRC
100
101#define KC_AMPR LSFT(KC_7) // &
102#define KC_AMPERSAND KC_AMPR
103
104#define KC_ASTR LSFT(KC_8) // *
105#define KC_ASTERISK KC_ASTR
106
107#define KC_LPRN LSFT(KC_9) // (
108#define KC_LEFT_PAREN KC_LPRN
109
110#define KC_RPRN LSFT(KC_0) // )
111#define KC_RIGHT_PAREN KC_RPRN
112
113#define KC_UNDS LSFT(KC_MINS) // _
114#define KC_UNDERSCORE KC_UNDS
115
116#define KC_PLUS LSFT(KC_EQL) // +
117
118#define KC_LCBR LSFT(KC_LBRC) // {
119#define KC_LEFT_CURLY_BRACE KC_LCBR
120
121#define KC_RCBR LSFT(KC_RBRC) // }
122#define KC_RIGHT_CURLY_BRACE KC_RCBR
123
124#define KC_COLN LSFT(KC_SCLN) // :
125#define KC_COLON KC_COLN
126
127#define KC_PIPE LSFT(KC_BSLS) // |
128
129#define KC_DELT KC_DELETE // Del key (four letter code)
130
131// Alias for function layers than expand past FN31
132#define FUNC(kc) kc | 0x2000
133
134// Aliases
135#define S(kc) LSFT(kc)
136#define F(kc) FUNC(kc)
137
138#define M(kc) kc | 0x3000
139
140#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)
141
142// These affect the backlight (if your keyboard has one).
143// We don't need to comment them out if your keyboard doesn't have a backlight,
144// since they don't take up any space.
145#define BL_ON 0x4009
146#define BL_OFF 0x4000
147#define BL_0 0x4000
148#define BL_1 0x4001
149#define BL_2 0x4002
150#define BL_3 0x4003
151#define BL_4 0x4004
152#define BL_5 0x4005
153#define BL_6 0x4006
154#define BL_7 0x4007
155#define BL_8 0x4008
156#define BL_9 0x4009
157#define BL_10 0x400A
158#define BL_11 0x400B
159#define BL_12 0x400C
160#define BL_13 0x400D
161#define BL_14 0x400E
162#define BL_15 0x400F
163#define BL_DEC 0x4010
164#define BL_INC 0x4011
165#define BL_TOGG 0x4012
166#define BL_STEP 0x4013
167
168#define RESET 0x5000
169#define DEBUG 0x5001
170
171// GOTO layer - 16 layers max
172// when:
173// ON_PRESS = 1
174// ON_RELEASE = 2
175// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default.
176#define TO(layer, when) (layer | 0x5100 | (when << 0x4))
177
178// Momentary switch layer - 256 layer max
179#define MO(layer) (layer | 0x5200)
180
181// Set default layer - 256 layer max
182#define DF(layer) (layer | 0x5300)
183
184// Toggle to layer - 256 layer max
185#define TG(layer) (layer | 0x5400)
186
187#define MIDI(n) (n | 0x6000)
188
189// M-od, T-ap - 256 keycode max
190#define MT(mod, kc) (kc | 0x7000 | ((mod & 0xF) << 8))
191#define CTL_T(kc) MT(0x1, kc)
192#define SFT_T(kc) MT(0x2, kc)
193#define ALT_T(kc) MT(0x4, kc)
194#define GUI_T(kc) MT(0x8, kc)
195#define C_S_T(kc) MT(0x3, kc) // Control + Shift e.g. for gnome-terminal
196#define MEH_T(kc) MT(0x7, kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl
197#define LCAG_T(kc) MT(0xD, kc) // Left control alt and gui
198#define ALL_T(kc) MT(0xF, kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
199
200// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap
201#define KC_HYPR HYPR(KC_NO)
202#define KC_MEH MEH(KC_NO)
203
204// L-ayer, T-ap - 256 keycode max, 16 layer max
205#define LT(layer, kc) (kc | 0x8000 | ((layer & 0xF) << 8))
206
207// For sending unicode codes.
208// You may not send codes over 1FFF -- this supports most of UTF8.
209// To have a key that sends out Œ, go UC(0x0152)
210#define UNICODE(n) (n | 0x8000)
211#define UC(n) UNICODE(n)
212
213
214#endif
diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h
new file mode 100644
index 000000000..e5ef39552
--- /dev/null
+++ b/quantum/keymap_extras/keymap_bepo.h
@@ -0,0 +1,311 @@
1/* Keymap macros for the French BÉPO layout - http://bepo.fr */
2#ifndef KEYMAP_BEPO_H
3#define KEYMAP_BEPO_H
4
5#include "keymap.h"
6
7// Alt gr
8#ifndef ALTGR
9#define ALTGR(kc) RALT(kc)
10#endif
11#ifndef ALGR
12#define ALGR(kc) ALTGR(kc)
13#endif
14#define BP_ALGR KC_RALT
15
16// Normal characters
17// First row (on usual keyboards)
18#define BP_DOLLAR KC_GRAVE // $
19#define BP_DLR BP_DOLLAR
20#define BP_DOUBLE_QUOTE KC_1 // "
21#define BP_DQOT BP_DOUBLE_QUOTE
22#define BP_LEFT_GUILLEMET KC_2 // «
23#define BP_LGIL BP_LEFT_GUILLEMET
24#define BP_RIGHT_GUILLEMET KC_3 // »
25#define BP_RGIL BP_RIGHT_GUILLEMET
26#define BP_LEFT_PAREN KC_4 // (
27#define BP_LPRN BP_LEFT_PAREN
28#define BP_RIGHT_PAREN KC_5 // )
29#define BP_RPRN BP_RIGHT_PAREN
30#define BP_AT KC_6 // @
31#define BP_PLUS KC_7 // +
32#define BP_MINUS KC_8 // -
33#define BP_MINS BP_MINUS
34#define BP_SLASH KC_9 // /
35#define BP_SLSH BP_SLASH
36#define BP_ASTERISK KC_0 // *
37#define BP_ASTR BP_ASTERISK
38#define BP_EQUAL KC_MINUS // =
39#define BP_EQL BP_EQUAL
40#define BP_PERCENT KC_EQUAL // %
41#define BP_PERC BP_PERCENT
42
43// Second row
44#define BP_B KC_Q
45#define BP_E_ACUTE KC_W // é
46#define BP_ECUT BP_E_ACUTE
47#define BP_P KC_E
48#define BP_O KC_R
49#define BP_E_GRAVE KC_T // è
50#define BP_EGRV BP_E_GRAVE
51#define BP_DEAD_CIRCUMFLEX KC_Y // dead ^
52#define BP_DCRC BP_DEAD_CIRCUMFLEX
53#define BP_V KC_U
54#define BP_D KC_I
55#define BP_L KC_O
56#define BP_J KC_P
57#define BP_Z KC_LBRACKET
58#define BP_W KC_RBRACKET
59
60// Third row
61#define BP_A KC_A
62#define BP_U KC_S
63#define BP_I KC_D
64#define BP_E KC_F
65#define BP_COMMA KC_G // ,
66#define BP_COMM BP_COMMA
67#define BP_C KC_H
68#define BP_T KC_J
69#define BP_S KC_K
70#define BP_R KC_L
71#define BP_N KC_SCOLON
72#define BP_M KC_QUOTE
73#define BP_C_CEDILLA KC_BSLASH // ç
74#define BP_CCED BP_C_CEDILLA
75
76// Fourth row
77#define BP_E_CIRCUMFLEX KC_NONUS_BSLASH // ê
78#define BP_ECRC BP_E_CIRCUMFLEX
79#define BP_A_GRAVE KC_Z // à
80#define BP_AGRV BP_A_GRAVE
81#define BP_Y KC_X
82#define BP_X KC_C
83#define BP_DOT KC_V // .
84#define BP_K KC_B
85#define BP_APOSTROPHE KC_N
86#define BP_APOS BP_APOSTROPHE // '
87#define BP_Q KC_M
88#define BP_G KC_COMMA
89#define BP_H KC_DOT
90#define BP_F KC_SLASH
91
92// Shifted characters
93// First row
94#define BP_HASH LSFT(BP_DOLLAR) // #
95#define BP_1 LSFT(KC_1)
96#define BP_2 LSFT(KC_2)
97#define BP_3 LSFT(KC_3)
98#define BP_4 LSFT(KC_4)
99#define BP_5 LSFT(KC_5)
100#define BP_6 LSFT(KC_6)
101#define BP_7 LSFT(KC_7)
102#define BP_8 LSFT(KC_8)
103#define BP_9 LSFT(KC_9)
104#define BP_0 LSFT(KC_0)
105#define BP_DEGREE LSFT(BP_EQUAL) // °
106#define BP_DEGR BP_DEGREE
107#define BP_GRAVE LSFT(BP_PERCENT) // `
108#define BP_GRV BP_GRAVE
109
110// Second row
111#define BP_EXCLAIM LSFT(BP_DEAD_CIRCUMFLEX) // !
112#define BP_EXLM BP_EXCLAIM
113
114// Third row
115#define BP_SCOLON LSFT(BP_COMMA) // ;
116#define BP_SCLN BP_SCOLON
117
118// Fourth row
119#define BP_COLON LSFT(BP_DOT) // :
120#define BP_COLN BP_COLON
121#define BP_QUESTION LSFT(BP_APOS) // ?
122#define BP_QEST BP_QUESTION
123
124// Space bar
125#define BP_NON_BREAKING_SPACE LSFT(KC_SPACE)
126#define BP_NBSP BP_NON_BREAKING_SPACE
127
128// AltGr-ed characters
129// First row
130#define BP_EN_DASH ALTGR(BP_DOLLAR) // –
131#define BP_NDSH BP_EN_DASH
132#define BP_EM_DASH ALTGR(KC_1) // —
133#define BP_MDSH BP_EM_DASH
134#define BP_LESS ALTGR(KC_2) // <
135#define BP_GREATER ALTGR(KC_3) // >
136#define BP_GRTR BP_GREATER
137#define BP_LBRACKET ALTGR(KC_4) // [
138#define BP_LBRC BP_LBRACKET
139#define BP_RBRACKET ALTGR(KC_5) // ]
140#define BP_RBRC BP_RBRACKET
141#define BP_CIRCUMFLEX ALTGR(KC_6) // ^
142#define BP_CIRC BP_CIRCUMFLEX
143#define BP_PLUS_MINUS ALTGR(KC_7) // ±
144#define BP_PSMS BP_PLUS_MINUS
145#define BP_MATH_MINUS ALTGR(KC_8) // −
146#define BP_MMNS BP_MATH_MINUS
147#define BP_OBELUS ALTGR(KC_9) // ÷
148#define BP_OBEL BP_OBELUS
149// more conventional name of the symbol
150#define BP_DIVISION_SIGN BP_OBELUS
151#define BP_DVSN BP_DIVISION_SIGN
152#define BP_TIMES ALTGR(KC_0) // ×
153#define BP_TIMS BP_TIMES
154#define BP_DIFFERENT ALTGR(BP_EQUAL) // ≠
155#define BP_DIFF BP_DIFFERENT
156#define BP_PERMILLE ALTGR(BP_PERCENT) // ‰
157#define BP_PMIL BP_PERMILLE
158
159// Second row
160#define BP_PIPE ALTGR(BP_B) // |
161#define BP_DEAD_ACUTE ALTGR(BP_E_ACUTE) // dead ´
162#define BP_DACT BP_DEAD_ACUTE
163#define BP_AMPERSAND ALTGR(BP_P) // &
164#define BP_AMPR BP_AMPERSAND
165#define BP_OE_LIGATURE ALTGR(BP_O) // œ
166#define BP_OE BP_OE_LIGATURE
167#define BP_DEAD_GRAVE ALTGR(BP_E_GRAVE) // `
168#define BP_DGRV BP_DEAD_GRAVE
169#define BP_INVERTED_EXCLAIM ALTGR(BP_DEAD_CIRCUMFLEX) // ¡
170#define BP_IXLM BP_INVERTED_EXCLAIM
171#define BP_DEAD_CARON ALTGR(BP_V) // dead ˇ
172#define BP_DCAR BP_DEAD_CARON
173#define BP_ETH ALTGR(BP_D) // ð
174#define BP_DEAD_SLASH ALTGR(BP_L) // dead /
175#define BP_DSLH BP_DEAD_SLASH
176#define BP_IJ_LIGATURE ALTGR(BP_J) // ij
177#define BP_IJ BP_IJ_LIGATURE
178#define BP_SCHWA ALTGR(BP_Z) // ə
179#define BP_SCWA BP_SCHWA
180#define BP_DEAD_BREVE ALTGR(BP_W) // dead ˘
181#define BP_DBRV BP_DEAD_BREVE
182
183// Third row
184#define BP_AE_LIGATURE ALTGR(BP_A) // æ
185#define BP_AE BP_AE_LIGATURE
186#define BP_U_GRAVE ALTGR(BP_U) // ù
187#define BP_UGRV BP_U_GRAVE
188#define BP_DEAD_TREMA ALTGR(BP_I) // dead ¨ (trema/umlaut/diaresis)
189#define BP_DTRM BP_DEAD_TREMA
190#define BP_EURO ALTGR(BP_E) // €
191#define BP_TYPOGRAPHICAL_APOSTROPHE ALTGR(BP_COMMMA) // ’
192#define BP_TAPO BP_TYPOGRAPHICAL_APOSTROPHE
193#define BP_COPYRIGHT ALTGR(BP_C) // ©
194#define BP_CPRT BP_COPYRIGHT
195#define BP_THORN ALTGR(BP_T) // þ
196#define BP_THRN BP_THORN
197#define BP_SHARP_S ALTGR(BP_S) // ß
198#define BP_SRPS BP_SHARP_S
199#define BP_REGISTERED_TRADEMARK ALTGR(BP_R) // ®
200#define BP_RTM BP_REGISTERED_TRADEMARK
201#define BP_DEAD_TILDE ALTGR(BP_N) // dead ~
202#define BP_DTLD BP_DEAD_TILDE
203#define BP_DEAD_MACRON ALTGR(BP_M) // dead ¯
204#define BP_DMCR BP_DEAD_MACRON
205#define BP_DEAD_CEDILLA ALTGR(BP_C_CEDILLA) // dead ¸
206#define BP_DCED BP_DEAD_CEDILLA
207
208// Fourth row
209#define BP_NONUS_SLASH ALTGR(BP_E_CIRCUMFLEX) // / on non-us backslash key (102nd key, ê in bépo)
210#define BP_NUSL BP_NONUS_SLASH
211#define BP_BACKSLASH ALTGR(BP_A_GRAVE) /* \ */
212#define BP_BSLS BP_BACKSLASH
213#define BP_LEFT_CURLY_BRACE ALTGR(BP_Y) // {
214#define BP_LCBR BP_LEFT_CURLY_BRACE
215#define BP_RIGHT_CURLY_BRACE ALTGR(BP_X) // }
216#define BP_RCBR BP_RIGHT_CURLY_BRACE
217#define BP_ELLIPSIS ALTGR(BP_DOT) // …
218#define BP_ELPS BP_ELLIPSIS
219#define BP_TILDE ALTGR(BP_K) // ~
220#define BP_TILD BP_TILDE
221#define BP_INVERTED_QUESTION ALTGR(BP_QUESTION) // ¿
222#define BP_IQST BP_INVERTED_QUESTION
223#define BP_DEAD_RING ALTGR(BP_Q) // dead °
224#define BP_DRNG BP_DEAD_RING
225#define BP_DEAD_GREEK ALTGR(BP_G) // dead Greek key (following key will make a Greek letter)
226#define BP_DGRK BP_DEAD_GREEK
227#define BP_DAGGER ALTGR(BP_H) // †
228#define BP_DAGR BP_DAGGER
229#define BP_DEAD_OGONEK ALTGR(BP_F) // dead ˛
230#define BP_DOGO BP_DEAD_OGONEK
231
232// Space bar
233#define BP_UNDERSCORE ALTGR(KC_SPACE) // _
234#define BP_UNDS BP_UNDERSCORE
235
236// AltGr-Shifted characters (different from capitalised AltGr-ed characters)
237// First row
238#define BP_PARAGRAPH ALTGR(BP_HASH) // ¶
239#define BP_PARG BP_PARAGRAPH
240#define BP_LOW_DOUBLE_QUOTE ALTGR(BP_1) // „
241#define BP_LWQT BP_LOW_DOUBLE_QUOTE
242#define BP_LEFT_DOUBLE_QUOTE ALTGR(BP_2) // “
243#define BP_LDQT BP_LEFT_DOUBLE_QUOTE
244#define BP_RIGHT_DOUBLE_QUOTE ALTGR(BP_3) // ”
245#define BP_RDQT BP_RIGHT_DOUBLE_QUOTE
246#define BP_LESS_OR_EQUAL ALTGR(BP_4) // ≤
247#define BP_LEQL BP_LESS_OR_EQUAL
248#define BP_GREATER_OR_EQUAL ALTGR(BP_5) // ≥
249#define BP_GEQL BP_GREATER_OR_EQUAL
250// nothing on ALTGR(BP_6)
251#define BP_NEGATION ALTGR(BP_7) // ¬
252#define BP_NEGT BP_NEGATION
253#define BP_ONE_QUARTER ALTGR(BP_8) // ¼
254#define BP_1QRT BP_ONE_QUARTER
255#define BP_ONE_HALF ALTGR(BP_9) // ½
256#define BP_1HLF BP_ONE_HALF
257#define BP_THREE_QUARTERS ALTGR(BP_0) // ¾
258#define BP_3QRT BP_THREE_QUARTERS
259#define BP_MINUTES ALTGR(BP_DEGREE) // ′
260#define BP_MNUT BP_MINUTES
261#define BP_SECONDS ALTGR(BP_GRAVE) // ″
262#define BP_SCND BP_SECONDS
263
264// Second row
265#define BP_BROKEN_PIPE LSFT(BP_PIPE) // ¦
266#define BP_BPIP BP_BROKEN_PIPE
267#define BP_DEAD_DOUBLE_ACUTE LSFT(BP_DEAD_ACUTE) // ˝
268#define BP_DDCT BP_DEAD_DOUBLE_ACUTE
269#define BP_SECTION ALTGR(LSFT(BP_P)) // §
270#define BP_SECT BP_SECTION
271// LSFT(BP_DEAD_GRAVE) is actually the same character as LSFT(BP_PERCENT)
272#define BP_GRAVE_BIS LSFT(BP_DEAD_GRAVE) // `
273#define BP_GRVB BP_GRAVE_BIS
274
275// Third row
276#define BP_DEAD_DOT_ABOVE LSFT(BP_DEAD_TREMA) // dead ˙
277#define BP_DDTA BP_DEAD_DOT_ABOVE
278#define BP_DEAD_CURRENCY LSFT(BP_EURO) // dead ¤ (next key will generate a currency code like ¥ or £)
279#define BP_DCUR BP_DEAD_CURRENCY
280#define BP_DEAD_HORN LSFT(ALTGR(BP_COMMA)) // dead ̛
281#define BP_DHRN BP_DEAD_HORN
282#define BP_LONG_S LSFT(ALTGR(BP_C)) // ſ
283#define BP_LNGS BP_LONG_S
284#define BP_TRADEMARK LSFT(BP_REGISTERED_TRADEMARK) // ™
285#define BP_TM BP_TRADEMARK
286#define BP_ORDINAL_INDICATOR_O LSFT(ALTGR(BP_M)) // º
287#define BP_ORDO BP_ORDINAL_INDICATOR_O
288#define BP_DEAD_COMMA LSFT(BP_DEAD_CEDILLA) // dead ˛
289#define BP_DCOM BP_DEAD_COMMA
290
291// Fourth row
292#define BP_LEFT_QUOTE LSFT(ALTGR(BP_Y)) // ‘
293#define BP_LQOT BP_LEFT_QUOTE
294#define BP_RIGHT_QUOTE LSFT(ALTGR(BP_X)) // ’
295#define BP_RQOT BP_RIGHT_QUOTE
296#define BP_INTERPUNCT LSFT(ALTGR(BP_DOT)) // ·
297#define BP_IPCT BP_INTERPUNCT
298#define BP_DEAD_HOOK_ABOVE LSFT(ALTGR(BP_QUESTION)) // dead ̉
299#define BP_DHKA BP_DEAD_HOOK_ABOVE
300#define BP_DEAD_UNDERDOT LSFT(BP_DEAD_RING) // dead ̣
301#define BP_DUDT BP_DEAD_UNDERDOT
302#define BP_DOUBLE_DAGGER LSFT(BP_DAGGER) // ‡
303#define BP_DDGR BP_DOUBLE_DAGGER
304#define BP_ORDINAL_INDICATOR_A LSFT(ALTGR(BP_F)) // ª
305#define BP_ORDA BP_ORDINAL_INDICATOR_A
306
307// Space bar
308#define BP_NARROW_NON_BREAKING_SPACE ALTGR(BP_NON_BREAKING_SPACE)
309#define BP_NNBS BP_NARROW_NON_BREAKING_SPACE
310
311#endif
diff --git a/quantum/keymap_extras/keymap_canadian_multilingual.h b/quantum/keymap_extras/keymap_canadian_multilingual.h
new file mode 100644
index 000000000..0bc20c7b9
--- /dev/null
+++ b/quantum/keymap_extras/keymap_canadian_multilingual.h
@@ -0,0 +1,255 @@
1#ifndef KEYMAP_CANADIAN_MULTILINGUAG_H
2#define KEYMAP_CANADIAN_MULTILINGUAG_H
3
4#include "keymap.h"
5
6// Alt gr
7#ifndef ALTGR
8#define ALTGR(kc) RALT(kc)
9#endif
10#ifndef ALGR
11#define ALGR(kc) ALTGR(kc)
12#endif
13
14#define CSA_ALTGR KC_RALT
15#define CSA_ALGR CSA_ALTGR
16
17#ifndef GR2A
18#define GR2A(kc) RCTL(kc)
19#endif
20
21// Normal characters
22// First row
23#define CSA_SLASH KC_GRV // /
24#define CSA_SLSH CSA_SLASH
25
26// Second row
27#define CSA_DEAD_CIRCUMFLEX KC_LBRACKET // dead ^
28#define CSA_DCRC CSA_DEAD_CIRCUMFLEX
29#define CSA_C_CEDILLA KC_RBRACKET // Ç
30#define CSA_CCED CSA_C_CEDILLA
31
32// Third row
33#define CSA_E_GRAVE KC_QUOT // è
34#define CSA_EGRV CSA_E_GRAVE
35#define CSA_A_GRAVE KC_BSLASH // à
36#define CSA_AGRV CSA_A_GRAVE
37
38// Fourth row
39#define CSA_U_GRAVE KC_NONUS_BSLASH // ù
40#define CSA_UGRV CSA_U_GRAVE
41#define CSA_E_ACUTE KC_SLSH // é
42#define CSA_ECUT CSA_E_ACUTE
43
44// Shifted characters
45// First row
46#define CSA_BACKSLASH LSFT(CSA_SLASH) /* \ */
47#define CSA_BSLS CSA_BACKSLASH
48#define CSA_QUESTION LSFT(KC_6) // ?
49#define CSA_QEST CSA_QUESTION
50
51// Second row
52#define CSA_DEAD_TREMA LSFT(CSA_DEAD_CIRCUMFLEX) // dead trema/umlaut/diaresis for ä ë ï ö ü
53#define CSA_DTRM CSA_DEAD_TREMA
54
55// Third row
56// all same as US-QWERTY, or capitalised character of the non-shifted key
57
58// Fourth row
59#define CSA_APOSTROPHE LSFT(KC_COMMA) // '
60#define CSA_APOS CSA_APOSTROPHE
61#define CSA_DOUBLE_QUOTE LSFT(KC_DOT) // "
62#define CSA_DQOT CSA_DOUBLE_QUOTE
63
64// Alt Gr-ed characters
65// First row
66#define CSA_PIPE ALTGR(CSA_SLASH) // |
67#define CSA_CURRENCY ALTGR(KC_4) // ¤
68#define CSA_CURR CSA_CURRENCY
69#define CSA_LEFT_CURLY_BRACE ALTGR(KC_7) // {
70#define CSA_LCBR CSA_LEFT_CURLY_BRACE
71#define CSA_RIGHT_CURLY_BRACE ALTGR(KC_8) // }
72#define CSA_RCBR CSA_RIGHT_CURLY_BRACE
73#define CSA_LBRACKET ALTGR(KC_9) // [
74#define CSA_LBRC CSA_LBRACKET
75#define CSA_RBRACKET ALTGR(KC_0) // ]
76#define CSA_RBRC CSA_RBRACKET
77#define CSA_NEGATION ALTGR(KC_EQUAL) // ¬
78#define CSA_NEGT CSA_NEGATION
79
80// Second row
81// euro symbol not available on Linux? (X.org)
82#define CSA_EURO ALTGR(KC_E) // €
83#define CSA_DEAD_GRAVE ALTGR(CSA_DEAD_CIRCUMFLEX)
84#define CSA_DGRV CSA_DEAD_GRAVE // dead `
85#define CSA_DEAD_TILDE ALTGR(CSA_C_CEDILLA) // ~
86#define CSA_DTLD CSA_DEAD_TILDE
87
88// Third row
89#define CSA_DEGREE ALTGR(KC_SCOLON) // °
90#define CSA_DEGR CSA_DEGREE
91
92// Fourth row
93#define CSA_LEFT_GUILLEMET ALTGR(KC_Z) // «
94#define CSA_LGIL CSA_LEFT_GUILLEMET
95#define CSA_RIGHT_GUILLEMET ALTGR(KC_X) // »
96#define CSA_RGIL CSA_RIGHT_GUILLEMET
97#define CSA_LESS ALTGR(KC_COMMA) // <
98#define CSA_GREATER ALTGR(KC_DOT) // >
99#define CSA_GRTR CSA_GREATER
100
101// Space bar
102#define CSA_NON_BREAKING_SPACE ALTGR(KC_SPACE)
103#define CSA_NBSP CSA_NON_BREAKING_SPACE
104
105// GR2A-ed characters
106// First row
107#define CSA_SUPERSCRIPT_ONE GR2A(KC_1) // ¹
108#define CSA_SUP1 CSA_SUPERSCRIPT_ONE
109#define CSA_SUPERSCRIPT_TWO GR2A(KC_2) // ²
110#define CSA_SUP2 CSA_SUPERSCRIPT_TWO
111#define CSA_SUPERSCRIPT_THREE GR2A(KC_3) // ³
112#define CSA_SUP3 CSA_SUPERSCRIPT_THREE
113#define CSA_ONE_QUARTER GR2A(KC_4) // ¼
114#define CSA_1QRT CSA_ONE_QUARTER
115#define CSA_ONE_HALF GR2A(KC_5) // ½
116#define CSA_1HLF CSA_ONE_HALF
117#define CSA_THREE_QUARTERS GR2A(KC_6) // ¾
118#define CSA_3QRT CSA_THREE_QUARTERS
119// nothing on 7-0 and -
120#define CSA_DEAD_CEDILLA GR2A(KC_EQUAL) // dead ¸
121#define CSA_DCED CSA_DEAD_CEDILLA
122
123// Second row
124#define CSA_OMEGA GR2A(KC_Q) // ω
125#define CSA_OMEG CSA_OMEGA
126#define CSA_L_STROKE GR2A(KC_W) // ł
127#define CSA_LSTK CSA_L_STROKE
128#define CSA_OE_LIGATURE GR2A(KC_E) // œ
129#define CSA_OE CSA_OE_LIGATURE
130#define CSA_PARAGRAPH GR2A(KC_R) // ¶
131#define CSA_PARG CSA_PARAGRAPH
132#define CSA_T_STROKE GR2A(KC_T) // ŧ
133#define CSA_LEFT_ARROW GR2A(KC_Y) // ←
134#define CSA_LARW CSA_LEFT_ARROW
135#define CSA_DOWN_ARROW GR2A(KC_U) // ↓
136#define CSA_DARW CSA_DOWN_ARROW
137#define CSA_RIGHT_ARROW GR2A(KC_I) // →
138#define CSA_RARW CSA_RIGHT_ARROW
139#define CSA_O_STROKE GR2A(KC_O) // ø
140#define CSA_OSTK CSA_O_STROKE
141#define CSA_THORN GR2A(KC_P) // þ
142#define CSA_THRN CSA_THORN
143// nothing on ^
144#define CSA_TILDE GR2A(CSA_C_CEDILLA) // dead ~
145#define CSA_TILD CSA_TILDE
146
147// Third row
148#define CSA_AE_LIGATURE GR2A(KC_A) // æ
149#define CSA_AE CSA_AE_LIGATURE
150#define CSA_SHARP_S GR2A(KC_S) // ß
151#define CSA_SRPS CSA_SHARP_S
152#define CSA_ETH GR2A(KC_D) // ð
153// nothing on F
154#define CSA_ENG GR2A(KC_G) // ŋ
155#define CSA_H_SRTOKE GR2A(KC_H) // ħ
156#define CSA_HSTK CSA_H_SRTOKE
157#define CSA_IJ_LIGATURE GR2A(KC_J) // ij
158#define CSA_IJ CSA_IJ_LIGATURE
159#define CSA_KRA GR2A(KC_K) // ĸ
160#define CSA_L_FLOWN_DOT GR2A(KC_L) // ŀ
161#define CSA_LFLD CSA_L_FLOWN_DOT
162#define CSA_DEAD_ACUTE GR2A(KC_SCLN) // dead acute accent
163#define CSA_DACT CSA_DEAD_ACUTE
164// nothing on È & À
165
166// Fourth row
167#define CSA_CENT GR2A(KC_C) // ¢
168#define CSA_LEFT_DOUBLE_QUOTE GR2A(KC_V) // “
169#define CSA_LDQT CSA_LEFT_DOUBLE_QUOTE
170#define CSA_RIGHT_DOUBLE_QUOTE GR2A(KC_B) // ”
171#define CSA_RDQT CSA_RIGHT_DOUBLE_QUOTE
172#define CSA_N_APOSTROPHE GR2A(KC_N) // ʼn (deprecated unicode codepoint)
173#define CSA_NAPO CSA_N_APOSTROPHE
174#define CSA_MU GR2A(KC_M) // μ
175#define CSA_HORIZONTAL_BAR GR2A(KC_COMMA) // ―
176#define CSA_HZBR CSA_HORIZONTAL_BAR
177#define CSA_DEAD_DOT_ABOVE GR2A(KC_DOT) // dead ˙
178#define CSA_DDTA CSA_DEAD_DOT_ABOVE
179
180// GR2A-shifted characters (different from capitalised GR2A-ed characters)
181// First row
182#define CSA_SOFT_HYPHEN GR2A(LSFT(CSA_SLASH)) // soft-hyphen, appears as a hyphen in wrapped word
183#define CSA_SHYP CSA_SOFT_HYPHEN
184#define CSA_INVERTED_EXCLAIM GR2A(KC_EXCLAIM) // ¡
185#define CSA_IXLM CSA_INVERTED_EXCLAIM
186// nothing on 2
187#define CSA_POUND GR2A(LSFT(KC_3)) // £
188#define CSA_GBP CSA_POUND_SIGN
189// already on ALTGR(KC_E)
190#define CSA_EURO_BIS GR2A(LSFT(KC_4)) // €
191#define CSA_EURB CSA_EURO_BIS
192#define CSA_THREE_EIGHTHS GR2A(LSFT(KC_5)) // ⅜
193#define CSA_3ON8 CSA_THREE_EIGHTHS
194#define CSA_FIVE_EIGHTHS GR2A(LSFT(KC_6)) // ⅝
195#define CSA_5ON8 CSA_FIVE_EIGHTHS
196#define CSA_SEVEN_EIGHTHS GR2A(LSFT(KC_7)) // ⅞
197#define CSA_7ON8 CSA_SEVEN_EIGHTHS
198#define CSA_TRADEMARK GR2A(LSFT(KC_8)) // ™
199#define CSA_TM CSA_TRADEMARK
200#define CSA_PLUS_MINUS GR2A(LSFT(KC_9)) // ±
201#define CSA_PSMS CSA_PLUS_MINUS
202// nothing on 0
203#define CSA_INVERTED_QUESTION GR2A(LSFT(KC_MINUS)) // ¿
204#define CSA_IQST CSA_INVERTED_QUESTION
205#define CSA_DEAD_OGONEK GR2A(LSFT(KC_EQUAL)) // dead ˛
206#define CSA_DOGO CSA_DEAD_OGONEK
207
208// Second row
209#define CSA_REGISTERED_TRADEMARK GR2A(LSFT(KC_R)) // ®
210#define CSA_RTM CSA_REGISTERED_TRADEMARK
211#define CSA_YEN GR2A(LSFT(KC_Y)) // ¥
212#define CSA_YUAN CSA_YEN
213#define CSA_UP_ARROW LSFT(CSA_DOWN_ARROW) // ↑
214#define CSA_DOTLESS_I GR2A(LSFT(KC_I)) // ı
215#define CSA_DLSI CSA_DOTLESS_I
216#define CSA_DEAD_RING GR2A(LSFT(CSA_DCRC)) // dead °
217#define CSA_DRNG CSA_DEAD_RING
218#define CSA_DEAD_MACRON GR2A(LSFT(CSA_C_CEDILLA)) // dead ¯
219#define CSA_DMCR CSA_DEAD_MACRON
220
221// Third row
222#define CSA_SECTION GR2A(LSFT(KC_S)) // §
223#define CSA_SECT CSA_SECTION
224#define CSA_ORDINAL_INDICATOR_A GR2A(LSFT(KC_F)) // ª
225#define CSA_ORDA CSA_ORDINAL_INDICATOR_A
226#define CSA_DEAD_DOUBLE_ACUTE LSFT(CSA_DEAD_ACUTE) // ˝
227#define CSA_DDCT CSA_DEAD_DOUBLE_ACUTE
228#define CSA_DEAD_CARON GR2A(LSFT(CSA_E_GRAVE)) // dead ˇ
229#define CSA_DCAR CSA_DEAD_CARON
230#define CSA_DEAD_BREVE GR2A(LSFT(CSA_A_GRAVE)) // dead ˘
231#define CSA_DBRV CSA_DEAD_BREVE
232
233// Fourth row
234#define CSA_BROKEN_PIPE GR2A(LSFT(CSA_U_GRAVE)) // ¦
235#define CSA_BPIP CSA_BROKEN_PIPE
236#define CSA_COPYRIGHT GR2A(LSFT(KC_C)) // ©
237#define CSA_CPRT CSA_COPYRIGHT
238#define CSA_LEFT_QUOTE GR2A(LSFT(KC_V)) // ‘
239#define CSA_LQOT CSA_LEFT_QUOTE
240#define CSA_RIGHT_QUOTE GR2A(LSFT(KC_B)) // ’
241#define CSA_RQOT CSA_RIGHT_QUOTE
242#define CSA_EIGHTH_NOTE GR2A(LSFT(KC_N)) // ♪
243#define CSA_8NOT CSA_EIGHTH_NOTE
244#define CSA_ORDINAL_INDICATOR_O GR2A(LSFT(KC_M)) // º
245#define CSA_ORDO CSA_ORDINAL_INDICATOR_O
246#define CSA_TIMES GR2A(LSFT(KC_COMMA)) // ×
247#define CSA_TIMS CSA_TIMES
248#define CSA_OBELUS GR2A(LSFT(KC_DOT)) // ÷
249#define CSA_OBEL CSA_OBELUS
250// more conventional name of the symbol
251#define CSA_DIVISION_SIGN CSA_OBELUS
252#define CSA_DVSN CSA_DIVISION_SIGN
253// TODO GR2A(LSFT(CSA_E_ACUTE))
254
255#endif
diff --git a/quantum/keymap_extras/keymap_colemak.h b/quantum/keymap_extras/keymap_colemak.h
index 8a418c615..b8d615748 100644
--- a/quantum/keymap_extras/keymap_colemak.h
+++ b/quantum/keymap_extras/keymap_colemak.h
@@ -1,7 +1,7 @@
1#ifndef KEYMAP_COLEMAK_H 1#ifndef KEYMAP_COLEMAK_H
2#define KEYMAP_COLEMAK_H 2#define KEYMAP_COLEMAK_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5// For software implementation of colemak 5// For software implementation of colemak
6#define CM_Q KC_Q 6#define CM_Q KC_Q
7#define CM_W KC_W 7#define CM_W KC_W
diff --git a/quantum/keymap_extras/keymap_dvorak.h b/quantum/keymap_extras/keymap_dvorak.h
index d172e0019..a0feed850 100644
--- a/quantum/keymap_extras/keymap_dvorak.h
+++ b/quantum/keymap_extras/keymap_dvorak.h
@@ -1,7 +1,7 @@
1#ifndef KEYMAP_DVORAK_H 1#ifndef KEYMAP_DVORAK_H
2#define KEYMAP_DVORAK_H 2#define KEYMAP_DVORAK_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Normal characters 6// Normal characters
7#define DV_GRV KC_GRV 7#define DV_GRV KC_GRV
@@ -18,18 +18,19 @@
18#define DV_LBRC KC_MINS 18#define DV_LBRC KC_MINS
19#define DV_RBRC KC_EQL 19#define DV_RBRC KC_EQL
20 20
21#define DV_QUOT KC_Q 21#define DV_QUOT KC_Q
22#define DV_COMM KC_W 22#define DV_COMM KC_W
23#define DV_DOT KC_E 23#define DV_DOT KC_E
24#define DV_P KC_R 24#define DV_P KC_R
25#define DV_Y KC_T 25#define DV_Y KC_T
26#define DV_F KC_Y 26#define DV_F KC_Y
27#define DV_G KC_U 27#define DV_G KC_U
28#define DV_C KC_I 28#define DV_C KC_I
29#define DV_R KC_O 29#define DV_R KC_O
30#define DV_L KC_P 30#define DV_L KC_P
31#define DV_SLSH KC_LBRC 31#define DV_SLSH KC_LBRC
32#define DV_EQL KC_RBRC 32#define DV_EQL KC_RBRC
33#define DV_BSLS KC_BSLS
33 34
34#define DV_A KC_A 35#define DV_A KC_A
35#define DV_O KC_S 36#define DV_O KC_S
@@ -69,4 +70,16 @@
69#define DV_LCBR LSFT(DV_LBRC) 70#define DV_LCBR LSFT(DV_LBRC)
70#define DV_RCBR LSFT(DV_RBRC) 71#define DV_RCBR LSFT(DV_RBRC)
71 72
72#endif \ No newline at end of file 73#define DV_DQUO LSFT(DV_QUOT)
74#define DV_LABK LSFT(DV_COMM)
75#define DV_RABK LSFT(DV_DOT)
76
77#define DV_QUES LSFT(DV_SLSH)
78#define DV_PLUS LSFT(DV_EQL)
79#define DV_PIPE LSFT(DV_BSLS)
80
81#define DV_UNDS LSFT(DV_MINS)
82
83#define DV_COLN LSFT(DV_SCLN)
84
85#endif
diff --git a/quantum/keymap_extras/keymap_dvp.h b/quantum/keymap_extras/keymap_dvp.h
new file mode 100644
index 000000000..83f49a52b
--- /dev/null
+++ b/quantum/keymap_extras/keymap_dvp.h
@@ -0,0 +1,82 @@
1#ifndef KEYMAP_DVP_H
2#define KEYMAP_DVP_H
3
4#include "keymap.h"
5
6// Normal characters
7#define DP_DLR KC_GRV
8#define DP_AMPR KC_1
9#define DP_LBRC KC_2
10#define DP_LCBR KC_3
11#define DP_RCBR KC_4
12#define DP_LPRN KC_5
13#define DP_EQL KC_6
14#define DP_ASTR KC_7
15#define DP_RPRN KC_8
16#define DP_PLUS KC_9
17#define DP_RBRC KC_0
18#define DP_EXLM KC_MINS
19#define DP_HASH KC_EQL
20
21#define DP_SCLN KC_Q
22#define DP_COMM KC_W
23#define DP_DOT KC_E
24#define DP_P KC_R
25#define DP_Y KC_T
26#define DP_F KC_Y
27#define DP_G KC_U
28#define DP_C KC_I
29#define DP_R KC_O
30#define DP_L KC_P
31#define DP_SLSH KC_LBRC
32#define DP_AT KC_RBRC
33#define DP_BSLS KC_BSLS
34
35#define DP_A KC_A
36#define DP_O KC_S
37#define DP_E KC_D
38#define DP_U KC_F
39#define DP_I KC_G
40#define DP_D KC_H
41#define DP_H KC_J
42#define DP_T KC_K
43#define DP_N KC_L
44#define DP_S KC_SCLN
45#define DP_MINS KC_QUOT
46
47#define DP_QUOT KC_Z
48#define DP_Q KC_X
49#define DP_J KC_C
50#define DP_K KC_V
51#define DP_X KC_B
52#define DP_B KC_N
53#define DP_M KC_M
54#define DP_W KC_COMM
55#define DP_V KC_DOT
56#define DP_Z KC_SLSH
57
58// Shifted characters
59#define DP_TILD LSFT(DP_DLR)
60#define DP_PERC LSFT(DP_AMPR)
61#define DP_7 LSFT(DP_LBRC)
62#define DP_5 LSFT(DP_LCBR)
63#define DP_3 LSFT(DP_RCBR)
64#define DP_1 LSFT(DP_LPRN)
65#define DP_9 LSFT(DP_EQL)
66#define DP_0 LSFT(DP_ASTR)
67#define DP_2 LSFT(DP_RPRN)
68#define DP_4 LSFT(DP_PLUS)
69#define DP_6 LSFT(DP_RBRC)
70#define DP_8 LSFT(DP_EXLM)
71#define DP_GRV LSFT(DP_HASH)
72
73#define DP_COLN LSFT(DP_SCLN)
74#define DP_LABK LSFT(DP_COMM)
75#define DP_RABK LSFT(DP_DOT)
76#define DP_QUES LSFT(DP_SLSH)
77#define DP_CIRC LSFT(DP_AT)
78#define DP_PIPE LSFT(DP_BSLS)
79#define DP_UNDS LSFT(DP_MINS)
80#define DP_DQUO LSFT(DP_QUOT)
81
82#endif
diff --git a/quantum/keymap_extras/keymap_fr_ch.h b/quantum/keymap_extras/keymap_fr_ch.h
new file mode 100644
index 000000000..87d4bb24c
--- /dev/null
+++ b/quantum/keymap_extras/keymap_fr_ch.h
@@ -0,0 +1,98 @@
1#ifndef KEYMAP_FR_CH
2#define KEYMAP_FR_CH
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) RALT(kc)
8#define FR_CH_ALGR KC_RALT
9
10// normal characters
11#define FR_CH_Z KC_Y
12#define FR_CH_Y KC_Z
13
14#define FR_CH_A KC_A
15#define FR_CH_B KC_B
16#define FR_CH_C KC_C
17#define FR_CH_D KC_D
18#define FR_CH_E KC_E
19#define FR_CH_F KC_F
20#define FR_CH_G KC_G
21#define FR_CH_H KC_H
22#define FR_CH_I KC_I
23#define FR_CH_J KC_J
24#define FR_CH_K KC_K
25#define FR_CH_L KC_L
26#define FR_CH_M KC_M
27#define FR_CH_N KC_N
28#define FR_CH_O KC_O
29#define FR_CH_P KC_P
30#define FR_CH_Q KC_Q
31#define FR_CH_R KC_R
32#define FR_CH_S KC_S
33#define FR_CH_T KC_T
34#define FR_CH_U KC_U
35#define FR_CH_V KC_V
36#define FR_CH_W KC_W
37#define FR_CH_X KC_X
38
39#define FR_CH_0 KC_0
40#define FR_CH_1 KC_1
41#define FR_CH_2 KC_2
42#define FR_CH_3 KC_3
43#define FR_CH_4 KC_4
44#define FR_CH_5 KC_5
45#define FR_CH_6 KC_6
46#define FR_CH_7 KC_7
47#define FR_CH_8 KC_8
48#define FR_CH_9 KC_9
49
50#define FR_CH_DOT KC_DOT
51#define FR_CH_COMM KC_COMM
52
53#define FR_CH_QUOT KC_MINS
54#define FR_CH_AE KC_QUOT
55#define FR_CH_UE KC_LBRC
56#define FR_CH_OE KC_SCLN
57
58#define FR_CH_CIRC KC_EQL // accent circumflex ^ and grave ` and ~
59#define FR_CH_LESS KC_NUBS // < and > and backslash
60#define FR_CH_MINS KC_SLSH // - and _
61#define FR_CH_DLR KC_BSLS // $, £ and }
62#define FR_CH_PARA KC_GRV // § and ring °
63#define FR_CH_DIAE KC_RBRC // accent ¨
64
65// shifted characters
66#define FR_CH_RING LSFT(KC_GRV) // °
67#define FR_CH_EXLM LSFT(KC_RBRC) // !
68#define FR_CH_PLUS LSFT(KC_1) // +
69#define FR_CH_DQOT LSFT(KC_2) // "
70#define FR_CH_ASTR LSFT(KC_3) // *
71#define FR_CH_PERC LSFT(KC_5) // %
72#define FR_CH_AMPR LSFT(KC_6) // &
73#define FR_CH_SLSH LSFT(KC_7) // /
74#define FR_CH_LPRN LSFT(KC_8) // (
75#define FR_CH_RPRN LSFT(KC_9) // )
76#define FR_CH_EQL LSFT(KC_0) // =
77#define FR_CH_QST LSFT(FR_CH_QUOT) // ?
78#define FR_CH_MORE LSFT(FR_CH_LESS) // >
79#define FR_CH_COLN LSFT(KC_DOT) // :
80#define FR_CH_SCLN LSFT(KC_COMM) // ;
81#define FR_CH_UNDS LSFT(FR_CH_MINS) // _
82#define FR_CH_CCED LSFT(KC_4) // ç
83#define FR_CH_GRV LSFT(FR_CH_CIRC) // accent grave `
84
85// Alt Gr-ed characters
86#define FR_CH_LCBR ALGR(KC_QUOT) // {
87#define FR_CH_LBRC ALGR(KC_LBRC) // [
88#define FR_CH_RBRC ALGR(KC_9) // ]
89#define FR_CH_RCBR ALGR(KC_0) // }
90#define FR_CH_BSLS ALGR(FR_CH_LESS) // backslash
91#define FR_CH_AT ALGR(KC_2) // @
92#define FR_CH_EURO ALGR(KC_E) // €
93#define FR_CH_TILD ALGR(FR_CH_CIRC) // ~
94#define FR_CH_PIPE ALGR(KC_1) // |
95#define FR_CH_HASH ALGR(KC_3) // #
96#define FR_CH_ACUT ALGR(FR_CH_QUOT) // accent acute ´
97
98#endif
diff --git a/quantum/keymap_extras/keymap_french.h b/quantum/keymap_extras/keymap_french.h
index ccfaed8f0..834c69650 100644
--- a/quantum/keymap_extras/keymap_french.h
+++ b/quantum/keymap_extras/keymap_french.h
@@ -1,10 +1,10 @@
1#ifndef KEYMAP_FRENCH_H 1#ifndef KEYMAP_FRENCH_H
2#define KEYMAP_FRENCH_H 2#define KEYMAP_FRENCH_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Alt gr 6// Alt gr
7#define ALGR(kc) kc | 0x1400 7#define ALGR(kc) RALT(kc)
8#define NO_ALGR KC_RALT 8#define NO_ALGR KC_RALT
9 9
10// Normal characters 10// Normal characters
@@ -75,9 +75,9 @@
75#define FR_CIRC ALGR(KC_9) 75#define FR_CIRC ALGR(KC_9)
76#define FR_AT ALGR(KC_0) 76#define FR_AT ALGR(KC_0)
77#define FR_RBRC ALGR(FR_RPRN) 77#define FR_RBRC ALGR(FR_RPRN)
78#define FR_LCBR ALGR(FR_EQL) 78#define FR_RCBR ALGR(FR_EQL)
79 79
80#define FR_EURO ALGR(KC_E) 80#define FR_EURO ALGR(KC_E)
81#define FR_BULT ALGR(FR_DLR) 81#define FR_BULT ALGR(FR_DLR)
82 82
83#endif \ No newline at end of file 83#endif
diff --git a/quantum/keymap_extras/keymap_french_osx.h b/quantum/keymap_extras/keymap_french_osx.h
index eb31bfb4d..004d73ee2 100644
--- a/quantum/keymap_extras/keymap_french_osx.h
+++ b/quantum/keymap_extras/keymap_french_osx.h
@@ -1,7 +1,7 @@
1#ifndef KEYMAP_FRENCH_OSX_H 1#ifndef KEYMAP_FRENCH_OSX_H
2#define KEYMAP_FRENCH_OSX_H 2#define KEYMAP_FRENCH_OSX_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Normal characters 6// Normal characters
7#define FR_AT KC_GRV 7#define FR_AT KC_GRV
diff --git a/quantum/keymap_extras/keymap_german.h b/quantum/keymap_extras/keymap_german.h
index dbad26f8a..7e2e0ed44 100644
--- a/quantum/keymap_extras/keymap_german.h
+++ b/quantum/keymap_extras/keymap_german.h
@@ -1,10 +1,10 @@
1#ifndef KEYMAP_GERMAN 1#ifndef KEYMAP_GERMAN
2#define KEYMAP_GERMAN 2#define KEYMAP_GERMAN
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Alt gr 6// Alt gr
7#define ALGR(kc) kc | 0x1400 7#define ALGR(kc) RALT(kc)
8#define DE_ALGR KC_RALT 8#define DE_ALGR KC_RALT
9 9
10// normal characters 10// normal characters
diff --git a/quantum/keymap_extras/keymap_german_ch.h b/quantum/keymap_extras/keymap_german_ch.h
new file mode 100644
index 000000000..b66d582a4
--- /dev/null
+++ b/quantum/keymap_extras/keymap_german_ch.h
@@ -0,0 +1,102 @@
1#ifndef KEYMAP_SWISS_GERMAN
2#define KEYMAP_SWISS_GERMAN
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) RALT(kc)
8#define CH_ALGR KC_RALT
9
10// normal characters
11#define CH_Z KC_Y
12#define CH_Y KC_Z
13
14#define CH_A KC_A
15#define CH_B KC_B
16#define CH_C KC_C
17#define CH_D KC_D
18#define CH_E KC_E
19#define CH_F KC_F
20#define CH_G KC_G
21#define CH_H KC_H
22#define CH_I KC_I
23#define CH_J KC_J
24#define CH_K KC_K
25#define CH_L KC_L
26#define CH_M KC_M
27#define CH_N KC_N
28#define CH_O KC_O
29#define CH_P KC_P
30#define CH_Q KC_Q
31#define CH_R KC_R
32#define CH_S KC_S
33#define CH_T KC_T
34#define CH_U KC_U
35#define CH_V KC_V
36#define CH_W KC_W
37#define CH_X KC_X
38
39#define CH_0 KC_0
40#define CH_1 KC_1
41#define CH_2 KC_2
42#define CH_3 KC_3
43#define CH_4 KC_4
44#define CH_5 KC_5
45#define CH_6 KC_6
46#define CH_7 KC_7
47#define CH_8 KC_8
48#define CH_9 KC_9
49
50#define CH_DOT KC_DOT
51#define CH_COMM KC_COMM
52
53#define CH_QUOT KC_MINS // ' ? ´
54#define CH_AE KC_QUOT
55#define CH_UE KC_LBRC
56#define CH_OE KC_SCLN
57
58#define CH_PARA KC_GRAVE // secction sign § and °
59#define CH_CARR KC_EQL // carret ^ ` ~
60#define CH_DIER KC_RBRC // dieresis ¨ ! ]
61#define CH_DLR KC_BSLS // $ £ }
62#define CH_LESS KC_NUBS // < and > and backslash
63#define CH_MINS KC_SLSH // - and _
64
65// shifted characters
66#define CH_RING LSFT(CH_PARA) // °
67#define CH_PLUS LSFT(KC_1) // +
68#define CH_DQOT LSFT(KC_2) // "
69#define CH_PAST LSFT(KC_3) // *
70#define CH_CELA LSFT(KC_4) // ç
71#define CH_PERC LSFT(KC_5) // %
72#define CH_AMPR LSFT(KC_6) // &
73#define CH_SLSH LSFT(KC_7) // /
74#define CH_LPRN LSFT(KC_8) // (
75#define CH_RPRN LSFT(KC_9) // )
76#define CH_EQL LSFT(KC_0) // =
77#define CH_QST LSFT(CH_QUOT) // ?
78#define CH_GRV LSFT(CH_CARR) // `
79#define CH_EXLM LSFT(CH_DIER) // !
80#define CH_POND LSFT(CH_DLR) // £
81#define CH_MORE LSFT(CH_LESS) // >
82#define CH_COLN LSFT(KC_DOT) // :
83#define CH_SCLN LSFT(KC_COMM) // ;
84#define CH_UNDS LSFT(CH_MINS) // _
85
86// Alt Gr-ed characters
87#define CH_BRBR ALGR(KC_1) // ¦ brocken bar
88#define CH_AT ALGR(KC_2) // @
89#define CH_HASH ALGR(KC_3) // #
90#define CH_NOTL ALGR(KC_6) // ¬ negative logic
91#define CH_PIPE ALGR(KC_7) // |
92#define CH_CENT ALGR(KC_8) // ¢ cent
93#define CH_ACUT ALGR(CH_QUOT) // ´
94#define CH_TILD ALGR(CH_CARR) // ~
95#define CH_EURO ALGR(KC_E) // €
96#define CH_LBRC ALGR(CH_UE) // [
97#define CH_RBRC ALGR(CH_DIER) // ]
98#define CH_LCBR ALGR(CH_AE) // {
99#define CH_RCBR ALGR(CH_DLR) // }
100#define CH_BSLS ALGR(CH_LESS) // backslash
101
102#endif
diff --git a/quantum/keymap_extras/keymap_german_osx.h b/quantum/keymap_extras/keymap_german_osx.h
index b011561e2..f63f06618 100644
--- a/quantum/keymap_extras/keymap_german_osx.h
+++ b/quantum/keymap_extras/keymap_german_osx.h
@@ -1,100 +1,97 @@
1#ifndef KEYMAP_GERMAN_OSX 1#ifndef KEYMAP_GERMAN_OSX
2#define KEYMAP_GERMAN_OSX 2#define KEYMAP_GERMAN_OSX
3 3
4#ifdef KEYMAP_GERMAN 4#include "keymap.h"
5 #warning redefining german keys
6#endif
7#include "keymap_common.h"
8 5
9// Alt gr 6// Alt gr
10 7
11// normal characters 8// normal characters
12#define DE_Z KC_Y 9#define DE_OSX_Z KC_Y
13#define DE_Y KC_Z 10#define DE_OSX_Y KC_Z
14 11
15#define DE_A KC_A 12#define DE_OSX_A KC_A
16#define DE_B KC_B 13#define DE_OSX_B KC_B
17#define DE_C KC_C 14#define DE_OSX_C KC_C
18#define DE_D KC_D 15#define DE_OSX_D KC_D
19#define DE_E KC_E 16#define DE_OSX_E KC_E
20#define DE_F KC_F 17#define DE_OSX_F KC_F
21#define DE_G KC_G 18#define DE_OSX_G KC_G
22#define DE_H KC_H 19#define DE_OSX_H KC_H
23#define DE_I KC_I 20#define DE_OSX_I KC_I
24#define DE_J KC_J 21#define DE_OSX_J KC_J
25#define DE_K KC_K 22#define DE_OSX_K KC_K
26#define DE_L KC_L 23#define DE_OSX_L KC_L
27#define DE_M KC_M 24#define DE_OSX_M KC_M
28#define DE_N KC_N 25#define DE_OSX_N KC_N
29#define DE_O KC_O 26#define DE_OSX_O KC_O
30#define DE_P KC_P 27#define DE_OSX_P KC_P
31#define DE_Q KC_Q 28#define DE_OSX_Q KC_Q
32#define DE_R KC_R 29#define DE_OSX_R KC_R
33#define DE_S KC_S 30#define DE_OSX_S KC_S
34#define DE_T KC_T 31#define DE_OSX_T KC_T
35#define DE_U KC_U 32#define DE_OSX_U KC_U
36#define DE_V KC_V 33#define DE_OSX_V KC_V
37#define DE_W KC_W 34#define DE_OSX_W KC_W
38#define DE_X KC_X 35#define DE_OSX_X KC_X
39 36
40#define DE_0 KC_0 37#define DE_OSX_0 KC_0
41#define DE_1 KC_1 38#define DE_OSX_1 KC_1
42#define DE_2 KC_2 39#define DE_OSX_2 KC_2
43#define DE_3 KC_3 40#define DE_OSX_3 KC_3
44#define DE_4 KC_4 41#define DE_OSX_4 KC_4
45#define DE_5 KC_5 42#define DE_OSX_5 KC_5
46#define DE_6 KC_6 43#define DE_OSX_6 KC_6
47#define DE_7 KC_7 44#define DE_OSX_7 KC_7
48#define DE_8 KC_8 45#define DE_OSX_8 KC_8
49#define DE_9 KC_9 46#define DE_OSX_9 KC_9
50 47
51#define DE_DOT KC_DOT 48#define DE_OSX_DOT KC_DOT
52#define DE_COMM KC_COMM 49#define DE_OSX_COMM KC_COMM
53 50
54#define DE_SS KC_MINS 51#define DE_OSX_SS KC_MINS
55#define DE_AE KC_QUOT 52#define DE_OSX_AE KC_QUOT
56#define DE_UE KC_LBRC 53#define DE_OSX_UE KC_LBRC
57#define DE_OE KC_SCLN 54#define DE_OSX_OE KC_SCLN
58 55
59#define DE_CIRC KC_NUBS // accent circumflex ^ and ring ° 56#define DE_OSX_CIRC KC_NUBS // accent circumflex ^ and ring °
60#define DE_ACUT KC_EQL // accent acute ´ and grave ` 57#define DE_OSX_ACUT KC_EQL // accent acute ´ and grave `
61#define DE_PLUS KC_RBRC // + and * and ~ 58#define DE_OSX_PLUS KC_RBRC // + and * and ~
62#define DE_HASH KC_BSLS // # and ' 59#define DE_OSX_HASH KC_BSLS // # and '
63#define DE_LESS KC_GRV // < and > and | 60#define DE_OSX_LESS KC_GRV // < and > and |
64#define DE_MINS KC_SLSH // - and _ 61#define DE_OSX_MINS KC_SLSH // - and _
65 62
66// shifted characters 63// shifted characters
67#define DE_RING LSFT(DE_CIRC) // ° 64#define DE_OSX_RING LSFT(DE_OSX_CIRC) // °
68#define DE_EXLM LSFT(KC_1) // ! 65#define DE_OSX_EXLM LSFT(KC_1) // !
69#define DE_DQOT LSFT(KC_2) // " 66#define DE_OSX_DQOT LSFT(KC_2) // "
70#define DE_PARA LSFT(KC_3) // § 67#define DE_OSX_PARA LSFT(KC_3) // §
71#define DE_DLR LSFT(KC_4) // $ 68#define DE_OSX_DLR LSFT(KC_4) // $
72#define DE_PERC LSFT(KC_5) // % 69#define DE_OSX_PERC LSFT(KC_5) // %
73#define DE_AMPR LSFT(KC_6) // & 70#define DE_OSX_AMPR LSFT(KC_6) // &
74#define DE_SLSH LSFT(KC_7) // / 71#define DE_OSX_SLSH LSFT(KC_7) // /
75#define DE_LPRN LSFT(KC_8) // ( 72#define DE_OSX_LPRN LSFT(KC_8) // (
76#define DE_RPRN LSFT(KC_9) // ) 73#define DE_OSX_RPRN LSFT(KC_9) // )
77#define DE_EQL LSFT(KC_0) // = 74#define DE_OSX_EQL LSFT(KC_0) // =
78#define DE_QST LSFT(DE_SS) // ? 75#define DE_OSX_QST LSFT(DE_OSX_SS) // ?
79#define DE_GRV LSFT(DE_ACUT) // ` 76#define DE_OSX_GRV LSFT(DE_OSX_ACUT) // `
80#define DE_ASTR LSFT(DE_PLUS) // * 77#define DE_OSX_ASTR LSFT(DE_OSX_PLUS) // *
81#define DE_QUOT LSFT(DE_HASH) // ' 78#define DE_OSX_QUOT LSFT(DE_OSX_HASH) // '
82#define DE_MORE LSFT(DE_LESS) // > 79#define DE_OSX_MORE LSFT(DE_OSX_LESS) // >
83#define DE_COLN LSFT(KC_DOT) // : 80#define DE_OSX_COLN LSFT(KC_DOT) // :
84#define DE_SCLN LSFT(KC_COMM) // ; 81#define DE_OSX_SCLN LSFT(KC_COMM) // ;
85#define DE_UNDS LSFT(DE_MINS) // _ 82#define DE_OSX_UNDS LSFT(DE_OSX_MINS) // _
86 83
87// Alt-ed characters 84// Alt-ed characters
88#define DE_SQ2 LALT(KC_2) // ² 85//#define DE_OSX_SQ2 LALT(KC_2) // ²
89#define DE_SQ3 LALT(KC_3) // ³ 86//#define DE_OSX_SQ3 LALT(KC_3) // ³
90#define DE_LCBR LALT(KC_7) // { 87#define DE_OSX_LCBR LALT(KC_8) // {
91#define DE_LBRC LALT(KC_5) // [ 88#define DE_OSX_LBRC LALT(KC_5) // [
92#define DE_RBRC LALT(KC_6) // ] 89#define DE_OSX_RBRC LALT(KC_6) // ]
93#define DE_RCBR LALT(KC_9) // } 90#define DE_OSX_RCBR LALT(KC_9) // }
94#define DE_BSLS LALT(LSFT(KC_7)) // backslash 91#define DE_OSX_BSLS LALT(LSFT(KC_7)) // backslash
95#define DE_AT LALT(DE_L) // @ 92#define DE_OSX_AT LALT(DE_OSX_L) // @
96#define DE_EURO LALT(KC_E) // € 93#define DE_OSX_EURO LALT(KC_E) // €
97#define DE_TILD LALT(DE_N) // ~ 94#define DE_OSX_TILD LALT(DE_OSX_N) // ~
98#define DE_PIPE LALT(DE_7) // | 95#define DE_OSX_PIPE LALT(DE_OSX_7) // |
99 96
100#endif 97#endif
diff --git a/quantum/keymap_extras/keymap_neo2.h b/quantum/keymap_extras/keymap_neo2.h
index 055d7d0d1..80439af34 100644
--- a/quantum/keymap_extras/keymap_neo2.h
+++ b/quantum/keymap_extras/keymap_neo2.h
@@ -1,8 +1,8 @@
1#ifndef KEYMAP_NEO2 1#ifndef KEYMAP_NEO2
2#define KEYMAP_NEO2 2#define KEYMAP_NEO2
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5#include "keymap_extras/keymap_german.h" 5#include "keymap_german.h"
6 6
7#define NEO_A KC_D 7#define NEO_A KC_D
8#define NEO_B KC_N 8#define NEO_B KC_N
@@ -35,6 +35,25 @@
35#define NEO_UE DE_Y 35#define NEO_UE DE_Y
36#define NEO_SS DE_UE 36#define NEO_SS DE_UE
37 37
38#define NEO_DOT DE_DOT
39#define NEO_COMM DE_COMM
40
41#define NEO_1 DE_1
42#define NEO_2 DE_2
43#define NEO_3 DE_3
44#define NEO_4 DE_4
45#define NEO_5 DE_5
46#define NEO_6 DE_6
47#define NEO_7 DE_7
48#define NEO_8 DE_8
49#define NEO_9 DE_9
50#define NEO_0 DE_0
51#define NEO_MINS DE_SS
52
53#define NEO_ACUT DE_PLUS
54#define NEO_GRV DE_ACUT
55#define NEO_CIRC DE_CIRC
56
38#define NEO_L1_L KC_CAPS 57#define NEO_L1_L KC_CAPS
39#define NEO_L1_R DE_HASH 58#define NEO_L1_R DE_HASH
40 59
diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h
index 7ef41fb79..da5c82975 100644
--- a/quantum/keymap_extras/keymap_nordic.h
+++ b/quantum/keymap_extras/keymap_nordic.h
@@ -1,10 +1,10 @@
1#ifndef KEYMAP_NORDIC_H 1#ifndef KEYMAP_NORDIC_H
2#define KEYMAP_NORDIC_H 2#define KEYMAP_NORDIC_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Alt gr 6// Alt gr
7#define ALGR(kc) kc | 0x1400 7#define ALGR(kc) RALT(kc)
8#define NO_ALGR KC_RALT 8#define NO_ALGR KC_RALT
9 9
10// Normal characters 10// Normal characters
@@ -25,7 +25,7 @@
25#define NO_SECT LSFT(NO_HALF) 25#define NO_SECT LSFT(NO_HALF)
26#define NO_QUO2 LSFT(KC_2) 26#define NO_QUO2 LSFT(KC_2)
27#define NO_BULT LSFT(KC_4) 27#define NO_BULT LSFT(KC_4)
28#define NO_AMP LSFT(KC_6) 28#define NO_AMPR LSFT(KC_6)
29#define NO_SLSH LSFT(KC_7) 29#define NO_SLSH LSFT(KC_7)
30#define NO_LPRN LSFT(KC_8) 30#define NO_LPRN LSFT(KC_8)
31#define NO_RPRN LSFT(KC_9) 31#define NO_RPRN LSFT(KC_9)
diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h
new file mode 100644
index 000000000..5c4e8c495
--- /dev/null
+++ b/quantum/keymap_extras/keymap_norwegian.h
@@ -0,0 +1,41 @@
1#ifndef KEYMAP_NORWEGIAN_H
2#define KEYMAP_NORWEGIAN_H
3
4#include "keymap_nordic.h"
5
6// There are slight differrences in the keyboards in the nordic contries
7
8// Norwegian redifinitions from the nordic keyset
9#undef NO_ACUT
10#define NO_ACUT ALGR(NO_BSLS) // ´
11#undef NO_AE
12#define NO_AE KC_QUOT // æ
13#undef NO_BSLS
14#define NO_BSLS KC_EQL // '\'
15#undef NO_CIRC
16#define NO_CIRC LSFT(KC_RBRC) // ^
17#undef NO_GRV
18#define NO_GRV LSFT(NO_BSLS) //
19#undef NO_OSLH
20#define NO_OSLH KC_SCLN // ø
21#undef NO_PIPE
22#define NO_PIPE KC_GRV // |
23
24// Additional norwegian keys not defined in the nordic keyset
25#define NO_AA KC_LBRC // å
26#define NO_ASTR LSFT(KC_BSLS) // *
27
28// Norwegian unique MAC characters
29#define NO_ACUT_MAC KC_EQL // =
30#define NO_APOS_MAC KC_NUBS // '
31#define NO_AT_MAC KC_BSLS // @
32#define NO_BSLS_MAC ALGR(LSFT(KC_7)) // '\'
33#define NO_DLR_MAC LSFT(KC_4) // $
34#define NO_GRV_MAC ALGR(NO_BSLS) // `
35#define NO_GRTR_MAC LSFT(KC_GRV) // >
36#define NO_LCBR_MAC ALGR(LSFT(KC_8)) // }
37#define NO_LESS_MAC KC_GRV // >
38#define NO_PIPE_MAC ALGR(KC_7) // |
39#define NO_RCBR_MAC ALGR(LSFT(KC_9)) // }
40
41#endif
diff --git a/quantum/keymap_extras/keymap_plover.h b/quantum/keymap_extras/keymap_plover.h
new file mode 100644
index 000000000..9b88f7d84
--- /dev/null
+++ b/quantum/keymap_extras/keymap_plover.h
@@ -0,0 +1,32 @@
1#ifndef KEYMAP_PLOVER_H
2#define KEYMAP_PLOVER_H
3
4#include "keymap.h"
5
6#define PV_NUM KC_1
7#define PV_LS KC_Q
8#define PV_LT KC_W
9#define PV_LP KC_E
10#define PV_LH KC_R
11#define PV_LK KC_S
12#define PV_LW KC_D
13#define PV_LR KC_F
14
15#define PV_STAR KC_Y
16#define PV_RF KC_U
17#define PV_RP KC_I
18#define PV_RL KC_O
19#define PV_RT KC_P
20#define PV_RD KC_LBRC
21#define PV_RR KC_J
22#define PV_RB KC_K
23#define PV_RG KC_L
24#define PV_RS KC_SCLN
25#define PV_RZ KC_QUOT
26
27#define PV_A KC_C
28#define PV_O KC_V
29#define PV_E KC_N
30#define PV_U KC_M
31
32#endif
diff --git a/quantum/keymap_extras/keymap_russian.h b/quantum/keymap_extras/keymap_russian.h
new file mode 100644
index 000000000..237e9abde
--- /dev/null
+++ b/quantum/keymap_extras/keymap_russian.h
@@ -0,0 +1,77 @@
1#ifndef KEYMAP_RUSSIAN_H
2#define KEYMAP_RUSSIAN_H
3
4#include "keymap.h"
5
6// Normal Chracters // reg SHIFT
7#define RU_A KC_F // а and А
8#define RU_BE KC_COMM // б and Б
9#define RU_VE KC_D // в and В
10#define RU_GHE KC_U // г and Г
11#define RU_DE KC_L // д and Д
12#define RU_IE KC_T // е and Е
13#define RU_IO KC_GRV // ё and Ё
14#define RU_ZHE KC_SCLN // ж and Ж
15#define RU_ZE KC_P // з and З
16#define RU_I KC_B // и and И
17#define RU_SRT_I KC_Q // й and Й
18#define RU_KA KC_R // к and К
19#define RU_EL KC_K // л and Л
20#define RU_EM KC_V // м and М
21#define RU_EN KC_Y // н and Н
22#define RU_O KC_J // о and О
23#define RU_PE KC_G // п and П
24#define RU_ER KC_H // р and Р
25#define RU_ES KC_C // с and С
26#define RU_TE KC_N // т and Т
27#define RU_U KC_E // у and У
28#define RU_EF KC_A // ф and Ф
29#define RU_HA KC_LBRC // х and Х
30#define RU_TSE KC_W // ц and Ц
31#define RU_CHE KC_X // ч and Ч
32#define RU_SHA KC_I // ш and Ш
33#define RU_SHCHA KC_O // щ and Щ
34#define RU_HSIGN KC_RBRC // ъ and Ъ
35#define RU_YERU KC_S // ы and Ы
36#define RU_SSIGN KC_M // ь and Ь
37#define RU_E KC_QUOT // э and Э
38#define RU_YU KC_DOT // ю and Ю
39#define RU_YA KC_Z // я and Я
40
41#define RU_1 KC_1 // 1 and !
42#define RU_2 KC_2 // 2 and "
43#define RU_3 KC_3 // 3 and №
44#define RU_4 KC_4 // 4 and ;
45#define RU_5 KC_5 // 5 and %
46#define RU_6 KC_6 // 6 and :
47#define RU_7 KC_7 // 7 and ?
48#define RU_8 KC_8 // 8 and *
49#define RU_9 KC_9 // 9 and (
50#define RU_0 KC_0 // 0 and )
51
52#define RU_MINS KC_MINS // - and _
53#define RU_EQL KC_EQL // = and +
54#define RU_BSLS KC_BSLS // \ and /
55#define RU_DOT KC_SLSH // . and ,
56
57// Shifted Chracters
58#define RU_EXLM LSFT(RU_1) // !
59#define RU_DQUT LSFT(RU_2) // "
60#define RU_NMRO LSFT(RU_3) // №
61#define RU_SCLN LSFT(RU_4) // ;
62#define RU_PERC LSFT(RU_5) // %
63#define RU_COLN LSFT(RU_6) // :
64#define RU_QUES LSFT(RU_7) // ?
65#define RU_ASTR LSFT(RU_8) // *
66#define RU_LPRN LSFT(RU_9) // (
67#define RU_RPRN LSFT(RU_0) // )
68
69#define RU_UNDR LSFT(RU_MINS) // _
70#define RU_PLUS LSFT(RU_EQL) // +
71#define RU_SLSH LSFT(RU_BSLS) // /
72#define RU_COMM LSFT(RU_DOT) // ,
73
74// Alt Gr-ed characters
75#define RU_RUBL RALT(RU_8) // ₽
76
77#endif
diff --git a/quantum/keymap_extras/keymap_spanish.h b/quantum/keymap_extras/keymap_spanish.h
index 7f980afbc..4ba568af2 100644
--- a/quantum/keymap_extras/keymap_spanish.h
+++ b/quantum/keymap_extras/keymap_spanish.h
@@ -1,10 +1,10 @@
1#ifndef KEYMAP_SPANISH_H 1#ifndef KEYMAP_SPANISH_H
2#define KEYMAP_SPANISH_H 2#define KEYMAP_SPANISH_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Alt gr 6// Alt gr
7#define ALGR(kc) kc | 0x1400 7#define ALGR(kc) RALT(kc)
8#define NO_ALGR KC_RALT 8#define NO_ALGR KC_RALT
9 9
10// Normal characters 10// Normal characters
@@ -49,7 +49,7 @@
49#define ES_PIPE ALGR(KC_1) 49#define ES_PIPE ALGR(KC_1)
50#define ES_AT ALGR(KC_2) 50#define ES_AT ALGR(KC_2)
51#define ES_HASH ALGR(KC_3) 51#define ES_HASH ALGR(KC_3)
52#define ES_TILD ALGR(KC_4) 52#define ES_TILD ALGR(ES_NTIL)
53#define ES_EURO ALGR(KC_5) 53#define ES_EURO ALGR(KC_5)
54#define ES_NOT ALGR(KC_6) 54#define ES_NOT ALGR(KC_6)
55 55
@@ -59,4 +59,4 @@
59#define ES_LCBR ALGR(ES_ACUT) 59#define ES_LCBR ALGR(ES_ACUT)
60#define ES_RCRB ALGR(ES_CCED) 60#define ES_RCRB ALGR(ES_CCED)
61 61
62#endif \ No newline at end of file 62#endif
diff --git a/quantum/keymap_extras/keymap_uk.h b/quantum/keymap_extras/keymap_uk.h
index 5b4bd3c0d..00c87afc3 100644
--- a/quantum/keymap_extras/keymap_uk.h
+++ b/quantum/keymap_extras/keymap_uk.h
@@ -1,10 +1,10 @@
1#ifndef KEYMAP_UK_H 1#ifndef KEYMAP_UK_H
2#define KEYMAP_UK_H 2#define KEYMAP_UK_H
3 3
4#include "keymap_common.h" 4#include "keymap.h"
5 5
6// Alt gr 6// Alt gr
7#define ALGR(kc) kc | 0x1400 7#define ALGR(kc) RALT(kc)
8#define NO_ALGR KC_RALT 8#define NO_ALGR KC_RALT
9 9
10// Normal characters 10// Normal characters
@@ -33,4 +33,4 @@
33 33
34#define UK_AACT ALGR(KC_A) 34#define UK_AACT ALGR(KC_A)
35 35
36#endif \ No newline at end of file 36#endif
diff --git a/quantum/keymap_extras/keymap_unicode_cyrillic.h b/quantum/keymap_extras/keymap_unicode_cyrillic.h
new file mode 100644
index 000000000..a40626d91
--- /dev/null
+++ b/quantum/keymap_extras/keymap_unicode_cyrillic.h
@@ -0,0 +1,163 @@
1#ifndef KEYMAP_CYRILLIC_H
2#define KEYMAP_CYRILLIC_H
3
4#include "keymap.h"
5
6/*
7 * This is based off of
8 * https://en.wikipedia.org/wiki/Cyrillic_script
9 *
10 * Unicode is iffy, a software implementation is preferred
11 */
12
13// Capital Char russian/ukrainian/bulgarian
14#define CY_A UC(0x0410) // А rus ukr bul
15#define CY_BE UC(0x0411) // Б rus ukr bul
16#define CY_VE UC(0x0412) // В rus ukr bul
17#define CY_GHE UC(0x0413) // Г rus ukr bul
18#define CY_GHEUP UC(0x0490) // Ґ ukr
19#define CY_DE UC(0x0414) // Д rus ukr bul
20#define CY_DJE UC(0x0402) // Ђ
21#define CY_GJE UC(0x0403) // Ѓ
22#define CY_IE UC(0x0415) // Е rus ukr bul
23#define CY_IO UC(0x0401) // Ё rus
24#define CY_UIE UC(0x0404) // Є ukr
25#define CY_ZHE UC(0x0416) // Ж rus ukr bul
26#define CY_ZE UC(0x0417) // З rus ukr bul
27#define CY_DZE UC(0x0405) // Ѕ
28#define CY_I UC(0x0418) // И rus ukr bul
29#define CY_B_U_I UC(0x0406) // І ukr
30#define CY_YI UC(0x0407) // Ї ukr
31#define CY_SRT_I UC(0x0419) // Й rus ukr bul
32#define CY_JE UC(0x0408) // Ј
33#define CY_KA UC(0x041a) // К rus ukr bul
34#define CY_EL UC(0x041b) // Л rus ukr bul
35#define CY_LJE UC(0x0409) // Љ
36#define CY_EM UC(0x041c) // М rus ukr bul
37#define CY_EN UC(0x041d) // Н rus ukr bul
38#define CY_NJE UC(0x040a) // Њ
39#define CY_O UC(0x041e) // О rus ukr bul
40#define CY_PE UC(0x041f) // П rus ukr bul
41#define CY_ER UC(0x0420) // Р rus ukr bul
42#define CY_ES UC(0x0421) // С rus ukr bul
43#define CY_TE UC(0x0422) // Т rus ukr bul
44#define CY_TSHE UC(0x040b) // Ћ
45#define CY_KJE UC(0x040c) // Ќ
46#define CY_U UC(0x0423) // У rus ukr bul
47#define CY_SRT_U UC(0x040e) // Ў
48#define CY_EF UC(0x0424) // Ф rus ukr bul
49#define CY_HA UC(0x0425) // Х rus bul
50#define CY_TSE UC(0x0426) // Ц rus ukr bul
51#define CY_CHE UC(0x0427) // Ч rus ukr bul
52#define CY_DZHE UC(0x040f) // Џ
53#define CY_SHA UC(0x0428) // Ш rus ukr bul
54#define CY_SHCHA UC(0x0429) // Щ rus ukr bul
55#define CY_HSIGN UC(0x042a) // Ъ rus bul
56#define CY_YERU UC(0x042b) // Ы rus
57#define CY_SSIGN UC(0x042c) // Ь rus ukr bul
58#define CY_E UC(0x042d) // Э rus
59#define CY_YU UC(0x042e) // Ю rus ukr bul
60#define CY_YA UC(0x042f) // Я rus ukr bul
61// Important Cyrillic non-Slavic letters
62#define CY_PALOCHKA UC(0x04c0) // Ӏ
63#define CY_SCHWA UC(0x04d8) // Ә
64#define CY_GHE_S UC(0x0492) // Ғ
65#define CY_ZE_D UC(0x0498) // Ҙ
66#define CY_ES_D UC(0x04aa) // Ҫ
67#define CY_BR_KA UC(0x04a0) // Ҡ
68#define CY_ZHE_D UC(0x0496) // Җ
69#define CY_KA_D UC(0x049a) // Қ
70#define CY_EN_D UC(0x04a2) // Ң
71#define CY_ENGHE UC(0x04a4) // Ҥ
72#define CY_BRD_O UC(0x04e8) // Ө
73#define CY_STR_U UC(0x04ae) // Ү
74#define CY_S_U_S UC(0x04b0) // Ұ
75#define CY_SHHA UC(0x04ba) // Һ
76#define CY_HA_D UC(0x04b2) // Ҳ
77
78
79// Small
80#define CY_a UC(0x0430) // a rus ukr bul
81#define CY_be UC(0x0431) // б rus ukr bul
82#define CY_ve UC(0x0432) // в rus ukr bul
83#define CY_ghe UC(0x0433) // г rus ukr bul
84#define CY_gheup UC(0x0491) // ґ ukr
85#define CY_de UC(0x0434) // д rus ukr bul
86#define CY_dje UC(0x0452) // ђ
87#define CY_gje UC(0x0453) // ѓ
88#define CY_ie UC(0x0435) // е rus ukr bul
89#define CY_io UC(0x0451) // ё rus
90#define CY_uie UC(0x0454) // є ukr
91#define CY_zhe UC(0x0436) // ж rus ukr bul
92#define CY_ze UC(0x0437) // з rus ukr bul
93#define CY_dze UC(0x0455) // ѕ
94#define CY_i UC(0x0438) // и rus ukr bul
95#define CY_b_u_i UC(0x0456) // і ukr
96#define CY_yi UC(0x0457) // ї ukr
97#define CY_srt_i UC(0x0439) // й rus ukr bul
98#define CY_je UC(0x0458) // ј
99#define CY_ka UC(0x043a) // к rus ukr bul
100#define CY_el UC(0x043b) // л rus ukr bul
101#define CY_lje UC(0x0459) // љ
102#define CY_em UC(0x043c) // м rus ukr bul
103#define CY_en UC(0x043d) // н rus ukr bul
104#define CY_nje UC(0x045a) // њ
105#define CY_o UC(0x043e) // о rus ukr bul
106#define CY_pe UC(0x043f) // п rus ukr bul
107#define CY_er UC(0x0440) // р rus ukr bul
108#define CY_es UC(0x0441) // с rus ukr bul
109#define CY_te UC(0x0442) // т rus ukr bul
110#define CY_tshe UC(0x045b) // ћ
111#define CY_kje UC(0x045c) // ќ
112#define CY_u UC(0x0443) // у rus ukr bul
113#define CY_srt_u UC(0x045e) // ў
114#define CY_ef UC(0x0444) // ф rus ukr bul
115#define CY_ha UC(0x0445) // х rus ukr bul
116#define CY_tse UC(0x0446) // ц rus ukr bul
117#define CY_che UC(0x0447) // ч rus ukr bul
118#define CY_dzhe UC(0x045f) // џ
119#define CY_sha UC(0x0448) // ш rus ukr bul
120#define CY_shcha UC(0x0449) // щ rus ukr bul
121#define CY_hsign UC(0x044a) // ъ rus bul
122#define CY_yeru UC(0x044b) // ы rus
123#define CY_ssign UC(0x044c) // ь rus ukr bul
124#define CY_e UC(0x044d) // э rus
125#define CY_yu UC(0x044e) // ю rus ukr bul
126#define CY_ya UC(0x044f) // я rus ukr bul
127// Important Cyrillic non-Slavic letters
128#define CY_palochka UC(0x04cf) // ӏ
129#define CY_schwa UC(0x04d9) // ә
130#define CY_ghe_s UC(0x0493) // ғ
131#define CY_ze_d UC(0x0499) // ҙ
132#define CY_es_d UC(0x04ab) // ҫ
133#define CY_br_ka UC(0x04a1) // ҡ
134#define CY_zhe_d UC(0x0497) // җ
135#define CY_ka_d UC(0x049b) // қ
136#define CY_en_d UC(0x04a3) // ң
137#define CY_enghe UC(0x04a5) // ҥ
138#define CY_brd_o UC(0x04e9) // ө
139#define CY_str_u UC(0x04af) // ү
140#define CY_s_u_s UC(0x04b1) // ұ
141#define CY_shha UC(0x04bb) // һ
142#define CY_ha_d UC(0x04b3) // ҳ
143
144
145// Extra
146#define CY_slr_ve UC(0x1c80) // ᲀ CYRILLIC SMALL LETTER ROUNDED VE
147#define CY_ll_de UC(0x1c81) // ᲁ CYRILLIC SMALL LETTER LONG-LEGGED DE
148#define CY_ZEMLYA UC(0xa640) // Ꙁ CYRILLIC CAPITAL LETTER ZEMLYA
149#define CY_zemlya UC(0xa641) // ꙁ CYRILLIC SMALL LETTER ZEMLYA
150#define CY_RV_DZE UC(0xa644) // Ꙅ CYRILLIC CAPITAL LETTER REVERSED DZE
151#define CY_rv_DZE UC(0xa645) // ꙅ CYRILLIC SMALL LETTER REVERSED DZE
152#define CY_slw_es UC(0x1c83) // ᲃ CYRILLIC SMALL LETTER WIDE ES
153#define CY_st_te UC(0x1c84) // ᲄ CYRILLIC SMALL LETTER TALL TE
154#define CY_3l_te UC(0x1c85) // ᲅ CYRILLIC SMALL LETTER THREE-LEGGED TE
155#define CY_thsign UC(0x1c86) // ᲆ CYRILLIC SMALL LETTER TALL HARD SIGN
156#define CY_YERUBY UC(0xa650) // Ꙑ CYRILLIC CAPITAL LETTER YERU WITH BACK YER
157#define CY_yeruby UC(0xa651) // ꙑ CYRILLIC SMALL LETTER YERU WITH BACK YER
158#define CY_RUBL UC(0x20bd) // ₽
159#define CY_NMRO UC(0x2116) // №
160
161// The letters Zje and Sje are made for other letters and accent marks
162
163#endif
diff --git a/quantum/keymap_midi.c b/quantum/keymap_midi.c
deleted file mode 100644
index e37ea3103..000000000
--- a/quantum/keymap_midi.c
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2Copyright 2015 Jack Humbert <jack.humb@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "keymap_common.h"
19#include "keymap_midi.h"
20
21uint8_t starting_note = 0x0C;
22int offset = 7;
23
24void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
25{
26 if (id != 0) {
27 if (record->event.pressed) {
28 midi_send_noteon(&midi_device, opt, (id & 0xFF), 127);
29 } else {
30 midi_send_noteoff(&midi_device, opt, (id & 0xFF), 127);
31 }
32 }
33
34 if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) {
35 if (record->event.pressed) {
36 starting_note++;
37 play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1)), 0xC);
38 midi_send_cc(&midi_device, 0, 0x7B, 0);
39 midi_send_cc(&midi_device, 1, 0x7B, 0);
40 midi_send_cc(&midi_device, 2, 0x7B, 0);
41 midi_send_cc(&midi_device, 3, 0x7B, 0);
42 midi_send_cc(&midi_device, 4, 0x7B, 0);
43 return;
44 } else {
45 stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1)));
46 stop_all_notes();
47 return;
48 }
49 }
50 if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) {
51 if (record->event.pressed) {
52 starting_note--;
53 play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1)), 0xC);
54 midi_send_cc(&midi_device, 0, 0x7B, 0);
55 midi_send_cc(&midi_device, 1, 0x7B, 0);
56 midi_send_cc(&midi_device, 2, 0x7B, 0);
57 midi_send_cc(&midi_device, 3, 0x7B, 0);
58 midi_send_cc(&midi_device, 4, 0x7B, 0);
59 return;
60 } else {
61 stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1)));
62 stop_all_notes();
63 return;
64 }
65 }
66
67 if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
68 offset++;
69 midi_send_cc(&midi_device, 0, 0x7B, 0);
70 midi_send_cc(&midi_device, 1, 0x7B, 0);
71 midi_send_cc(&midi_device, 2, 0x7B, 0);
72 midi_send_cc(&midi_device, 3, 0x7B, 0);
73 midi_send_cc(&midi_device, 4, 0x7B, 0);
74 stop_all_notes();
75 for (int i = 0; i <= 7; i++) {
76 play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1)), 0xC);
77 _delay_us(80000);
78 stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1)));
79 _delay_us(8000);
80 }
81 return;
82 }
83 if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
84 offset--;
85 midi_send_cc(&midi_device, 0, 0x7B, 0);
86 midi_send_cc(&midi_device, 1, 0x7B, 0);
87 midi_send_cc(&midi_device, 2, 0x7B, 0);
88 midi_send_cc(&midi_device, 3, 0x7B, 0);
89 midi_send_cc(&midi_device, 4, 0x7B, 0);
90 stop_all_notes();
91 for (int i = 0; i <= 7; i++) {
92 play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1)), 0xC);
93 _delay_us(80000);
94 stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1)));
95 _delay_us(8000);
96 }
97 return;
98 }
99
100 if (record->event.pressed) {
101 // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
102 midi_send_noteon(&midi_device, 0, (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row), 127);
103 play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)), 0xF);
104 } else {
105 // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
106 midi_send_noteoff(&midi_device, 0, (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row), 127);
107 stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)));
108 }
109} \ No newline at end of file
diff --git a/quantum/keymap_unicode.c b/quantum/keymap_unicode.c
deleted file mode 100644
index a44965e61..000000000
--- a/quantum/keymap_unicode.c
+++ /dev/null
@@ -1,61 +0,0 @@
1/*
2Copyright 2015 Jack Humbert <jack.humb@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "keymap_common.h"
19
20uint16_t hextokeycode(int hex) {
21 if (hex == 0x0) {
22 return KC_0;
23 } else if (hex < 0xA) {
24 return KC_1 + (hex - 0x1);
25 } else {
26 return KC_A + (hex - 0xA);
27 }
28}
29
30void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
31{
32
33 // For more info on how this works per OS, see here: https://en.wikipedia.org/wiki/Unicode_input#Hexadecimal_code_input
34
35 if (record->event.pressed) {
36 uint16_t unicode = (opt << 8) | id;
37 register_code(KC_LALT);
38
39 register_code(hextokeycode((unicode & 0xF000) >> 12));
40 unregister_code(hextokeycode((unicode & 0xF000) >> 12));
41 register_code(hextokeycode((unicode & 0x0F00) >> 8));
42 unregister_code(hextokeycode((unicode & 0x0F00) >> 8));
43 register_code(hextokeycode((unicode & 0x00F0) >> 4));
44 unregister_code(hextokeycode((unicode & 0x00F0) >> 4));
45 register_code(hextokeycode((unicode & 0x000F)));
46 unregister_code(hextokeycode((unicode & 0x000F)));
47
48 /* Test 'a' */
49 // register_code(hextokeycode(0x0));
50 // unregister_code(hextokeycode(0x0));
51 // register_code(hextokeycode(0x0));
52 // unregister_code(hextokeycode(0x0));
53 // register_code(hextokeycode(0x6));
54 // unregister_code(hextokeycode(0x6));
55 // register_code(hextokeycode(0x1));
56 // unregister_code(hextokeycode(0x1));
57
58 unregister_code(KC_LALT);
59 }
60 return;
61} \ No newline at end of file
diff --git a/quantum/led.c b/quantum/led.c
deleted file mode 100644
index 2c0574660..000000000
--- a/quantum/led.c
+++ /dev/null
@@ -1,38 +0,0 @@
1/*
2Copyright 2012 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <avr/io.h>
19#include "stdint.h"
20#include "led.h"
21
22
23void led_set(uint8_t usb_led)
24{
25 // // Using PE6 Caps Lock LED
26 // if (usb_led & (1<<USB_LED_CAPS_LOCK))
27 // {
28 // // Output high.
29 // DDRE |= (1<<6);
30 // PORTE |= (1<<6);
31 // }
32 // else
33 // {
34 // // Output low.
35 // DDRE &= ~(1<<6);
36 // PORTE &= ~(1<<6);
37 // }
38}
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c
index f20043067..401845e85 100755
--- a/quantum/light_ws2812.c
+++ b/quantum/light_ws2812.c
@@ -19,12 +19,16 @@
19// Setleds for standard RGB 19// Setleds for standard RGB
20void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) 20void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
21{ 21{
22 ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); 22 // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
23 ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF));
23} 24}
24 25
25void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) 26void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
26{ 27{
27 ws2812_DDRREG |= pinmask; // Enable DDR 28 // ws2812_DDRREG |= pinmask; // Enable DDR
29 // new universal format (DDR)
30 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask;
31
28 ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); 32 ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
29 _delay_us(50); 33 _delay_us(50);
30} 34}
@@ -32,14 +36,17 @@ void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pin
32// Setleds for SK6812RGBW 36// Setleds for SK6812RGBW
33void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) 37void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
34{ 38{
35 ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR 39 // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
36 ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin)); 40 // new universal format (DDR)
41 _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF);
42
43 ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF));
37 _delay_us(80); 44 _delay_us(80);
38} 45}
39 46
40void ws2812_sendarray(uint8_t *data,uint16_t datlen) 47void ws2812_sendarray(uint8_t *data,uint16_t datlen)
41{ 48{
42 ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin)); 49 ws2812_sendarray_mask(data,datlen,_BV(RGB_DI_PIN & 0xF));
43} 50}
44 51
45/* 52/*
@@ -108,8 +115,10 @@ void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
108 uint8_t curbyte,ctr,masklo; 115 uint8_t curbyte,ctr,masklo;
109 uint8_t sreg_prev; 116 uint8_t sreg_prev;
110 117
111 masklo =~maskhi&ws2812_PORTREG; 118 // masklo =~maskhi&ws2812_PORTREG;
112 maskhi |= ws2812_PORTREG; 119 // maskhi |= ws2812_PORTREG;
120 masklo =~maskhi&_SFR_IO8((RGB_DI_PIN >> 4) + 2);
121 maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2);
113 sreg_prev=SREG; 122 sreg_prev=SREG;
114 cli(); 123 cli();
115 124
@@ -173,7 +182,7 @@ w_nop16
173 " dec %0 \n\t" // '1' [+2] '0' [+2] 182 " dec %0 \n\t" // '1' [+2] '0' [+2]
174 " brne loop%=\n\t" // '1' [+3] '0' [+4] 183 " brne loop%=\n\t" // '1' [+3] '0' [+4]
175 : "=&d" (ctr) 184 : "=&d" (ctr)
176 : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo) 185 : "r" (curbyte), "I" (_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r" (maskhi), "r" (masklo)
177 ); 186 );
178 } 187 }
179 188
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 95bf4c097..3174e0739 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -1,6 +1,6 @@
1/* 1/*
2Copyright 2012 Jun Wako 2Copyright 2012 Jun Wako
3Generated by planckkeyboard.com (2014 Jack Humbert) 3Copyright 2014 Jack Humbert
4 4
5This program is free software: you can redistribute it and/or modify 5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by 6it under the terms of the GNU General Public License as published by
@@ -15,23 +15,26 @@ GNU General Public License for more details.
15You should have received a copy of the GNU General Public License 15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>. 16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/ 17*/
18
19/*
20 * scan matrix
21 */
22#include <stdint.h> 18#include <stdint.h>
23#include <stdbool.h> 19#include <stdbool.h>
20#if defined(__AVR__)
24#include <avr/io.h> 21#include <avr/io.h>
25#include <util/delay.h> 22#endif
23#include "wait.h"
26#include "print.h" 24#include "print.h"
27#include "debug.h" 25#include "debug.h"
28#include "util.h" 26#include "util.h"
29#include "matrix.h" 27#include "matrix.h"
30 28
31#ifndef DEBOUNCE 29/* Set 0 if debouncing isn't needed */
32# define DEBOUNCE 10 30
31#ifndef DEBOUNCING_DELAY
32# define DEBOUNCING_DELAY 5
33#endif 33#endif
34static uint8_t debouncing = DEBOUNCE; 34static uint8_t debouncing = DEBOUNCING_DELAY;
35
36static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
37static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
35 38
36/* matrix state(1:on, 0:off) */ 39/* matrix state(1:on, 0:off) */
37static matrix_row_t matrix[MATRIX_ROWS]; 40static matrix_row_t matrix[MATRIX_ROWS];
@@ -42,39 +45,85 @@ static matrix_row_t matrix_debouncing[MATRIX_ROWS];
42 static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS]; 45 static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS];
43#endif 46#endif
44 47
48#if MATRIX_COLS > 16
49 #define SHIFTER 1UL
50#else
51 #define SHIFTER 1
52#endif
53
45static matrix_row_t read_cols(void); 54static matrix_row_t read_cols(void);
46static void init_cols(void); 55static void init_cols(void);
47static void unselect_rows(void); 56static void unselect_rows(void);
48static void select_row(uint8_t row); 57static void select_row(uint8_t row);
49 58
50__attribute__ ((weak)) 59__attribute__ ((weak))
51void * matrix_init_kb(void) { 60void matrix_init_quantum(void) {
61 matrix_init_kb();
62}
63
64__attribute__ ((weak))
65void matrix_scan_quantum(void) {
66 matrix_scan_kb();
67}
52 68
53}; 69__attribute__ ((weak))
70void matrix_init_kb(void) {
71 matrix_init_user();
72}
73
74__attribute__ ((weak))
75void matrix_scan_kb(void) {
76 matrix_scan_user();
77}
54 78
55__attribute__ ((weak)) 79__attribute__ ((weak))
56void * matrix_scan_kb(void) { 80void matrix_init_user(void) {
81}
57 82
58}; 83__attribute__ ((weak))
84void matrix_scan_user(void) {
85}
59 86
60inline 87inline
61uint8_t matrix_rows(void) 88uint8_t matrix_rows(void) {
62{
63 return MATRIX_ROWS; 89 return MATRIX_ROWS;
64} 90}
65 91
66inline 92inline
67uint8_t matrix_cols(void) 93uint8_t matrix_cols(void) {
68{
69 return MATRIX_COLS; 94 return MATRIX_COLS;
70} 95}
71 96
72void matrix_init(void) 97// void matrix_power_up(void) {
73{ 98// #if DIODE_DIRECTION == COL2ROW
99// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
100// /* DDRxn */
101// _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
102// toggle_row(r);
103// }
104// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
105// /* PORTxn */
106// _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
107// }
108// #else
109// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
110// /* DDRxn */
111// _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
112// toggle_col(c);
113// }
114// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
115// /* PORTxn */
116// _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
117// }
118// #endif
119// }
120
121void matrix_init(void) {
74 // To use PORTF disable JTAG with writing JTD bit twice within four cycles. 122 // To use PORTF disable JTAG with writing JTD bit twice within four cycles.
75 MCUCR |= (1<<JTD); 123 #ifdef __AVR_ATmega32U4__
76 MCUCR |= (1<<JTD); 124 MCUCR |= _BV(JTD);
77 125 MCUCR |= _BV(JTD);
126 #endif
78 127
79 // initialize row and col 128 // initialize row and col
80 unselect_rows(); 129 unselect_rows();
@@ -86,33 +135,30 @@ void matrix_init(void)
86 matrix_debouncing[i] = 0; 135 matrix_debouncing[i] = 0;
87 } 136 }
88 137
89 if (matrix_init_kb) { 138 matrix_init_quantum();
90 (*matrix_init_kb)();
91 }
92} 139}
93 140
94
95uint8_t matrix_scan(void) 141uint8_t matrix_scan(void)
96{ 142{
97 143
98#if DIODE_DIRECTION == COL2ROW 144#if DIODE_DIRECTION == COL2ROW
99 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 145 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
100 select_row(i); 146 select_row(i);
101 _delay_us(30); // without this wait read unstable value. 147 wait_us(30); // without this wait read unstable value.
102 matrix_row_t cols = read_cols(); 148 matrix_row_t cols = read_cols();
103 if (matrix_debouncing[i] != cols) { 149 if (matrix_debouncing[i] != cols) {
104 matrix_debouncing[i] = cols; 150 matrix_debouncing[i] = cols;
105 if (debouncing) { 151 if (debouncing) {
106 debug("bounce!: "); debug_hex(debouncing); debug("\n"); 152 debug("bounce!: "); debug_hex(debouncing); debug("\n");
107 } 153 }
108 debouncing = DEBOUNCE; 154 debouncing = DEBOUNCING_DELAY;
109 } 155 }
110 unselect_rows(); 156 unselect_rows();
111 } 157 }
112 158
113 if (debouncing) { 159 if (debouncing) {
114 if (--debouncing) { 160 if (--debouncing) {
115 _delay_ms(1); 161 wait_ms(1);
116 } else { 162 } else {
117 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 163 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
118 matrix[i] = matrix_debouncing[i]; 164 matrix[i] = matrix_debouncing[i];
@@ -122,21 +168,21 @@ uint8_t matrix_scan(void)
122#else 168#else
123 for (uint8_t i = 0; i < MATRIX_COLS; i++) { 169 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
124 select_row(i); 170 select_row(i);
125 _delay_us(30); // without this wait read unstable value. 171 wait_us(30); // without this wait read unstable value.
126 matrix_row_t rows = read_cols(); 172 matrix_row_t rows = read_cols();
127 if (matrix_reversed_debouncing[i] != rows) { 173 if (matrix_reversed_debouncing[i] != rows) {
128 matrix_reversed_debouncing[i] = rows; 174 matrix_reversed_debouncing[i] = rows;
129 if (debouncing) { 175 if (debouncing) {
130 debug("bounce!: "); debug_hex(debouncing); debug("\n"); 176 debug("bounce!: "); debug_hex(debouncing); debug("\n");
131 } 177 }
132 debouncing = DEBOUNCE; 178 debouncing = DEBOUNCING_DELAY;
133 } 179 }
134 unselect_rows(); 180 unselect_rows();
135 } 181 }
136 182
137 if (debouncing) { 183 if (debouncing) {
138 if (--debouncing) { 184 if (--debouncing) {
139 _delay_ms(1); 185 wait_ms(1);
140 } else { 186 } else {
141 for (uint8_t i = 0; i < MATRIX_COLS; i++) { 187 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
142 matrix_reversed[i] = matrix_reversed_debouncing[i]; 188 matrix_reversed[i] = matrix_reversed_debouncing[i];
@@ -152,9 +198,7 @@ uint8_t matrix_scan(void)
152 } 198 }
153#endif 199#endif
154 200
155 if (matrix_scan_kb) { 201 matrix_scan_quantum();
156 (*matrix_scan_kb)();
157 }
158 202
159 return 1; 203 return 1;
160} 204}
@@ -198,32 +242,16 @@ uint8_t matrix_key_count(void)
198 242
199static void init_cols(void) 243static void init_cols(void)
200{ 244{
201 int B = 0, C = 0, D = 0, E = 0, F = 0;
202
203#if DIODE_DIRECTION == COL2ROW 245#if DIODE_DIRECTION == COL2ROW
204 for(int x = 0; x < MATRIX_COLS; x++) { 246 for(int x = 0; x < MATRIX_COLS; x++) {
205 int col = COLS[x]; 247 int pin = col_pins[x];
206#else 248#else
207 for(int x = 0; x < MATRIX_ROWS; x++) { 249 for(int x = 0; x < MATRIX_ROWS; x++) {
208 int col = ROWS[x]; 250 int pin = row_pins[x];
209#endif 251#endif
210 if ((col & 0xF0) == 0x20) { 252 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
211 B |= (1<<(col & 0x0F)); 253 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
212 } else if ((col & 0xF0) == 0x30) {
213 C |= (1<<(col & 0x0F));
214 } else if ((col & 0xF0) == 0x40) {
215 D |= (1<<(col & 0x0F));
216 } else if ((col & 0xF0) == 0x50) {
217 E |= (1<<(col & 0x0F));
218 } else if ((col & 0xF0) == 0x60) {
219 F |= (1<<(col & 0x0F));
220 }
221 } 254 }
222 DDRB &= ~(B); PORTB |= (B);
223 DDRC &= ~(C); PORTC |= (C);
224 DDRD &= ~(D); PORTD |= (D);
225 DDRE &= ~(E); PORTE |= (E);
226 DDRF &= ~(F); PORTF |= (F);
227} 255}
228 256
229static matrix_row_t read_cols(void) 257static matrix_row_t read_cols(void)
@@ -232,80 +260,38 @@ static matrix_row_t read_cols(void)
232 260
233#if DIODE_DIRECTION == COL2ROW 261#if DIODE_DIRECTION == COL2ROW
234 for(int x = 0; x < MATRIX_COLS; x++) { 262 for(int x = 0; x < MATRIX_COLS; x++) {
235 int col = COLS[x]; 263 int pin = col_pins[x];
236#else 264#else
237 for(int x = 0; x < MATRIX_ROWS; x++) { 265 for(int x = 0; x < MATRIX_ROWS; x++) {
238 int col = ROWS[x]; 266 int pin = row_pins[x];
239#endif 267#endif
240 268 result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x);
241 if ((col & 0xF0) == 0x20) {
242 result |= (PINB&(1<<(col & 0x0F)) ? 0 : (1<<x));
243 } else if ((col & 0xF0) == 0x30) {
244 result |= (PINC&(1<<(col & 0x0F)) ? 0 : (1<<x));
245 } else if ((col & 0xF0) == 0x40) {
246 result |= (PIND&(1<<(col & 0x0F)) ? 0 : (1<<x));
247 } else if ((col & 0xF0) == 0x50) {
248 result |= (PINE&(1<<(col & 0x0F)) ? 0 : (1<<x));
249 } else if ((col & 0xF0) == 0x60) {
250 result |= (PINF&(1<<(col & 0x0F)) ? 0 : (1<<x));
251 }
252 } 269 }
253 return result; 270 return result;
254} 271}
255 272
256static void unselect_rows(void) 273static void unselect_rows(void)
257{ 274{
258 int B = 0, C = 0, D = 0, E = 0, F = 0;
259
260#if DIODE_DIRECTION == COL2ROW 275#if DIODE_DIRECTION == COL2ROW
261 for(int x = 0; x < MATRIX_ROWS; x++) { 276 for(int x = 0; x < MATRIX_ROWS; x++) {
262 int row = ROWS[x]; 277 int pin = row_pins[x];
263#else 278#else
264 for(int x = 0; x < MATRIX_COLS; x++) { 279 for(int x = 0; x < MATRIX_COLS; x++) {
265 int row = COLS[x]; 280 int pin = col_pins[x];
266#endif 281#endif
267 if ((row & 0xF0) == 0x20) { 282 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
268 B |= (1<<(row & 0x0F)); 283 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
269 } else if ((row & 0xF0) == 0x30) {
270 C |= (1<<(row & 0x0F));
271 } else if ((row & 0xF0) == 0x40) {
272 D |= (1<<(row & 0x0F));
273 } else if ((row & 0xF0) == 0x50) {
274 E |= (1<<(row & 0x0F));
275 } else if ((row & 0xF0) == 0x60) {
276 F |= (1<<(row & 0x0F));
277 }
278 } 284 }
279 DDRB &= ~(B); PORTB |= (B);
280 DDRC &= ~(C); PORTC |= (C);
281 DDRD &= ~(D); PORTD |= (D);
282 DDRE &= ~(E); PORTE |= (E);
283 DDRF &= ~(F); PORTF |= (F);
284} 285}
285 286
286static void select_row(uint8_t row) 287static void select_row(uint8_t row)
287{ 288{
288 289
289#if DIODE_DIRECTION == COL2ROW 290#if DIODE_DIRECTION == COL2ROW
290 int row_pin = ROWS[row]; 291 int pin = row_pins[row];
291#else 292#else
292 int row_pin = COLS[row]; 293 int pin = col_pins[row];
293#endif 294#endif
294 295 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF);
295 if ((row_pin & 0xF0) == 0x20) { 296 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF);
296 DDRB |= (1<<(row_pin & 0x0F)); 297}
297 PORTB &= ~(1<<(row_pin & 0x0F));
298 } else if ((row_pin & 0xF0) == 0x30) {
299 DDRC |= (1<<(row_pin & 0x0F));
300 PORTC &= ~(1<<(row_pin & 0x0F));
301 } else if ((row_pin & 0xF0) == 0x40) {
302 DDRD |= (1<<(row_pin & 0x0F));
303 PORTD &= ~(1<<(row_pin & 0x0F));
304 } else if ((row_pin & 0xF0) == 0x50) {
305 DDRE |= (1<<(row_pin & 0x0F));
306 PORTE &= ~(1<<(row_pin & 0x0F));
307 } else if ((row_pin & 0xF0) == 0x60) {
308 DDRF |= (1<<(row_pin & 0x0F));
309 PORTF &= ~(1<<(row_pin & 0x0F));
310 }
311} \ No newline at end of file
diff --git a/quantum/process_keycode/process_chording.c b/quantum/process_keycode/process_chording.c
new file mode 100644
index 000000000..d7814629f
--- /dev/null
+++ b/quantum/process_keycode/process_chording.c
@@ -0,0 +1,60 @@
1#include "process_chording.h"
2
3bool keys_chord(uint8_t keys[]) {
4 uint8_t keys_size = sizeof(keys)/sizeof(keys[0]);
5 bool pass = true;
6 uint8_t in = 0;
7 for (uint8_t i = 0; i < chord_key_count; i++) {
8 bool found = false;
9 for (uint8_t j = 0; j < keys_size; j++) {
10 if (chord_keys[i] == (keys[j] & 0xFF)) {
11 in++; // detects key in chord
12 found = true;
13 break;
14 }
15 }
16 if (found)
17 continue;
18 if (chord_keys[i] != 0) {
19 pass = false; // makes sure rest are blank
20 }
21 }
22 return (pass && (in == keys_size));
23}
24
25bool process_chording(uint16_t keycode, keyrecord_t *record) {
26 if (keycode >= QK_CHORDING && keycode <= QK_CHORDING_MAX) {
27 if (record->event.pressed) {
28 if (!chording) {
29 chording = true;
30 for (uint8_t i = 0; i < CHORDING_MAX; i++)
31 chord_keys[i] = 0;
32 chord_key_count = 0;
33 chord_key_down = 0;
34 }
35 chord_keys[chord_key_count] = (keycode & 0xFF);
36 chord_key_count++;
37 chord_key_down++;
38 return false;
39 } else {
40 if (chording) {
41 chord_key_down--;
42 if (chord_key_down == 0) {
43 chording = false;
44 // Chord Dictionary
45 if (keys_chord((uint8_t[]){KC_ENTER, KC_SPACE})) {
46 register_code(KC_A);
47 unregister_code(KC_A);
48 return false;
49 }
50 for (uint8_t i = 0; i < chord_key_count; i++) {
51 register_code(chord_keys[i]);
52 unregister_code(chord_keys[i]);
53 return false;
54 }
55 }
56 }
57 }
58 }
59 return true;
60} \ No newline at end of file
diff --git a/quantum/process_keycode/process_chording.h b/quantum/process_keycode/process_chording.h
new file mode 100644
index 000000000..49c97db3b
--- /dev/null
+++ b/quantum/process_keycode/process_chording.h
@@ -0,0 +1,16 @@
1#ifndef PROCESS_CHORDING_H
2#define PROCESS_CHORDING_H
3
4#include "quantum.h"
5
6// Chording stuff
7#define CHORDING_MAX 4
8bool chording = false;
9
10uint8_t chord_keys[CHORDING_MAX] = {0};
11uint8_t chord_key_count = 0;
12uint8_t chord_key_down = 0;
13
14bool process_chording(uint16_t keycode, keyrecord_t *record);
15
16#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c
new file mode 100644
index 000000000..e53d221e7
--- /dev/null
+++ b/quantum/process_keycode/process_leader.c
@@ -0,0 +1,38 @@
1#include "process_leader.h"
2
3__attribute__ ((weak))
4void leader_start(void) {}
5
6__attribute__ ((weak))
7void leader_end(void) {}
8
9// Leader key stuff
10bool leading = false;
11uint16_t leader_time = 0;
12
13uint16_t leader_sequence[5] = {0, 0, 0, 0, 0};
14uint8_t leader_sequence_size = 0;
15
16bool process_leader(uint16_t keycode, keyrecord_t *record) {
17 // Leader key set-up
18 if (record->event.pressed) {
19 if (!leading && keycode == KC_LEAD) {
20 leader_start();
21 leading = true;
22 leader_time = timer_read();
23 leader_sequence_size = 0;
24 leader_sequence[0] = 0;
25 leader_sequence[1] = 0;
26 leader_sequence[2] = 0;
27 leader_sequence[3] = 0;
28 leader_sequence[4] = 0;
29 return false;
30 }
31 if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) {
32 leader_sequence[leader_sequence_size] = keycode;
33 leader_sequence_size++;
34 return false;
35 }
36 }
37 return true;
38} \ No newline at end of file
diff --git a/quantum/process_keycode/process_leader.h b/quantum/process_keycode/process_leader.h
new file mode 100644
index 000000000..c83db8abb
--- /dev/null
+++ b/quantum/process_keycode/process_leader.h
@@ -0,0 +1,23 @@
1#ifndef PROCESS_LEADER_H
2#define PROCESS_LEADER_H
3
4#include "quantum.h"
5
6bool process_leader(uint16_t keycode, keyrecord_t *record);
7
8void leader_start(void);
9void leader_end(void);
10
11#ifndef LEADER_TIMEOUT
12 #define LEADER_TIMEOUT 200
13#endif
14#define SEQ_ONE_KEY(key) if (leader_sequence[0] == (key) && leader_sequence[1] == 0 && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0)
15#define SEQ_TWO_KEYS(key1, key2) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0)
16#define SEQ_THREE_KEYS(key1, key2, key3) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3) && leader_sequence[3] == 0 && leader_sequence[4] == 0)
17#define SEQ_FOUR_KEYS(key1, key2, key3, key4) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3) && leader_sequence[3] == (key4) && leader_sequence[4] == 0)
18#define SEQ_FIVE_KEYS(key1, key2, key3, key4, key5) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3) && leader_sequence[3] == (key4) && leader_sequence[4] == (key5))
19
20#define LEADER_EXTERNS() extern bool leading; extern uint16_t leader_time; extern uint16_t leader_sequence[5]; extern uint8_t leader_sequence_size
21#define LEADER_DICTIONARY() if (leading && timer_elapsed(leader_time) > LEADER_TIMEOUT)
22
23#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c
new file mode 100644
index 000000000..577dad43a
--- /dev/null
+++ b/quantum/process_keycode/process_midi.c
@@ -0,0 +1,68 @@
1#include "process_midi.h"
2
3bool midi_activated = false;
4uint8_t midi_starting_note = 0x0C;
5int midi_offset = 7;
6
7bool process_midi(uint16_t keycode, keyrecord_t *record) {
8 if (keycode == MI_ON && record->event.pressed) {
9 midi_activated = true;
10#ifdef AUDIO_ENABLE
11 music_scale_user();
12#endif
13 return false;
14 }
15
16 if (keycode == MI_OFF && record->event.pressed) {
17 midi_activated = false;
18 midi_send_cc(&midi_device, 0, 0x7B, 0);
19 return false;
20 }
21
22 if (midi_activated) {
23 if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) {
24 if (record->event.pressed) {
25 midi_starting_note++; // Change key
26 midi_send_cc(&midi_device, 0, 0x7B, 0);
27 }
28 return false;
29 }
30 if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) {
31 if (record->event.pressed) {
32 midi_starting_note--; // Change key
33 midi_send_cc(&midi_device, 0, 0x7B, 0);
34 }
35 return false;
36 }
37 if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
38 midi_offset++; // Change scale
39 midi_send_cc(&midi_device, 0, 0x7B, 0);
40 return false;
41 }
42 if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
43 midi_offset--; // Change scale
44 midi_send_cc(&midi_device, 0, 0x7B, 0);
45 return false;
46 }
47 // basic
48 // uint8_t note = (midi_starting_note + SCALE[record->event.key.col + midi_offset])+12*(MATRIX_ROWS - record->event.key.row);
49 // advanced
50 // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+12*(MATRIX_ROWS - record->event.key.row);
51 // guitar
52 uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+5*(MATRIX_ROWS - record->event.key.row);
53 // violin
54 // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+7*(MATRIX_ROWS - record->event.key.row);
55
56 if (record->event.pressed) {
57 // midi_send_noteon(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127);
58 midi_send_noteon(&midi_device, 0, note, 127);
59 } else {
60 // midi_send_noteoff(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127);
61 midi_send_noteoff(&midi_device, 0, note, 127);
62 }
63
64 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
65 return false;
66 }
67 return true;
68}
diff --git a/quantum/keymap_midi.h b/quantum/process_keycode/process_midi.h
index a89420ce2..acd4fc1b1 100644
--- a/quantum/keymap_midi.h
+++ b/quantum/process_keycode/process_midi.h
@@ -1,35 +1,20 @@
1/* 1#ifndef PROCESS_MIDI_H
2Copyright 2015 Jack Humbert <jack.humb@gmail.com> 2#define PROCESS_MIDI_H
3 3
4This program is free software: you can redistribute it and/or modify 4#include "quantum.h"
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8 5
9This program is distributed in the hope that it will be useful, 6bool process_midi(uint16_t keycode, keyrecord_t *record);
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13 7
14You should have received a copy of the GNU General Public License 8#define MIDI(n) ((n) | 0x6000)
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef KEYMAP_MIDI_H
19#define KEYMAP_MIDI_H
20
21#include <lufa.h>
22
23#define MIDI 0x6000
24#define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000 9#define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000
25 10
26#define CHNL(note, channel) (note + (channel << 8)) 11#define CHNL(note, channel) (note + (channel << 8))
27 12
28#define SCALE (int []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ 13#define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \
29 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ 14 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \
30 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ 15 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \
31 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ 16 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \
32 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } 17 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), }
33 18
34#define N_CN1 (0x600C + (12 * -1) + 0 ) 19#define N_CN1 (0x600C + (12 * -1) + 0 )
35#define N_CN1S (0x600C + (12 * -1) + 1 ) 20#define N_CN1S (0x600C + (12 * -1) + 1 )
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c
new file mode 100644
index 000000000..2d52e47a7
--- /dev/null
+++ b/quantum/process_keycode/process_music.c
@@ -0,0 +1,176 @@
1#include "process_music.h"
2
3bool music_activated = false;
4uint8_t starting_note = 0x0C;
5int offset = 7;
6
7// music sequencer
8static bool music_sequence_recording = false;
9static bool music_sequence_recorded = false;
10static bool music_sequence_playing = false;
11static float music_sequence[16] = {0};
12static uint8_t music_sequence_count = 0;
13static uint8_t music_sequence_position = 0;
14
15static uint16_t music_sequence_timer = 0;
16static uint16_t music_sequence_interval = 100;
17
18bool process_music(uint16_t keycode, keyrecord_t *record) {
19
20 if (keycode == AU_ON && record->event.pressed) {
21 audio_on();
22 return false;
23 }
24
25 if (keycode == AU_OFF && record->event.pressed) {
26 audio_off();
27 return false;
28 }
29
30 if (keycode == AU_TOG && record->event.pressed) {
31 if (is_audio_on())
32 {
33 audio_off();
34 }
35 else
36 {
37 audio_on();
38 }
39 return false;
40 }
41
42 if (keycode == MU_ON && record->event.pressed) {
43 music_on();
44 return false;
45 }
46
47 if (keycode == MU_OFF && record->event.pressed) {
48 music_off();
49 return false;
50 }
51
52 if (keycode == MU_TOG && record->event.pressed) {
53 if (music_activated)
54 {
55 music_off();
56 }
57 else
58 {
59 music_on();
60 }
61 return false;
62 }
63
64 if (keycode == MUV_IN && record->event.pressed) {
65 voice_iterate();
66 music_scale_user();
67 return false;
68 }
69
70 if (keycode == MUV_DE && record->event.pressed) {
71 voice_deiterate();
72 music_scale_user();
73 return false;
74 }
75
76 if (music_activated) {
77
78 if (keycode == KC_LCTL && record->event.pressed) { // Start recording
79 stop_all_notes();
80 music_sequence_recording = true;
81 music_sequence_recorded = false;
82 music_sequence_playing = false;
83 music_sequence_count = 0;
84 return false;
85 }
86
87 if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing
88 stop_all_notes();
89 if (music_sequence_recording) { // was recording
90 music_sequence_recorded = true;
91 }
92 music_sequence_recording = false;
93 music_sequence_playing = false;
94 return false;
95 }
96
97 if (keycode == KC_LGUI && record->event.pressed && music_sequence_recorded) { // Start playing
98 stop_all_notes();
99 music_sequence_recording = false;
100 music_sequence_playing = true;
101 music_sequence_position = 0;
102 music_sequence_timer = 0;
103 return false;
104 }
105
106 if (keycode == KC_UP) {
107 if (record->event.pressed)
108 music_sequence_interval-=10;
109 return false;
110 }
111
112 if (keycode == KC_DOWN) {
113 if (record->event.pressed)
114 music_sequence_interval+=10;
115 return false;
116 }
117
118 float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row));
119 if (record->event.pressed) {
120 play_note(freq, 0xF);
121 if (music_sequence_recording) {
122 music_sequence[music_sequence_count] = freq;
123 music_sequence_count++;
124 }
125 } else {
126 stop_note(freq);
127 }
128
129 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
130 return false;
131 }
132 return true;
133}
134
135bool is_music_on(void) {
136 return (music_activated != 0);
137}
138
139void music_toggle(void) {
140 if (!music_activated) {
141 music_on();
142 } else {
143 music_off();
144 }
145}
146
147void music_on(void) {
148 music_activated = 1;
149 music_on_user();
150}
151
152void music_off(void) {
153 music_activated = 0;
154 stop_all_notes();
155}
156
157
158__attribute__ ((weak))
159void music_on_user() {}
160
161__attribute__ ((weak))
162void audio_on_user() {}
163
164__attribute__ ((weak))
165void music_scale_user() {}
166
167void matrix_scan_music(void) {
168 if (music_sequence_playing) {
169 if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) {
170 music_sequence_timer = timer_read();
171 stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]);
172 play_note(music_sequence[music_sequence_position], 0xF);
173 music_sequence_position = (music_sequence_position + 1) % music_sequence_count;
174 }
175 }
176}
diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h
new file mode 100644
index 000000000..318b3e387
--- /dev/null
+++ b/quantum/process_keycode/process_music.h
@@ -0,0 +1,27 @@
1#ifndef PROCESS_MUSIC_H
2#define PROCESS_MUSIC_H
3
4#include "quantum.h"
5
6bool process_music(uint16_t keycode, keyrecord_t *record);
7
8bool is_music_on(void);
9void music_toggle(void);
10void music_on(void);
11void music_off(void);
12
13void audio_on_user(void);
14void music_on_user(void);
15void music_scale_user(void);
16
17void matrix_scan_music(void);
18
19#ifndef SCALE
20#define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \
21 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \
22 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \
23 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \
24 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), }
25#endif
26
27#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
new file mode 100644
index 000000000..6ae362c4c
--- /dev/null
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -0,0 +1,136 @@
1#include "quantum.h"
2#include "action_tapping.h"
3
4static uint16_t last_td;
5static int8_t highest_td = -1;
6
7void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data) {
8 qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
9
10 if (state->count == 1) {
11 register_code16 (pair->kc1);
12 } else if (state->count == 2) {
13 register_code16 (pair->kc2);
14 }
15}
16
17void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) {
18 qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
19
20 if (state->count == 1) {
21 unregister_code16 (pair->kc1);
22 } else if (state->count == 2) {
23 unregister_code16 (pair->kc2);
24 }
25}
26
27static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
28 void *user_data,
29 qk_tap_dance_user_fn_t fn)
30{
31 if (fn) {
32 fn(state, user_data);
33 }
34}
35
36static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t *action)
37{
38 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_each_tap);
39}
40
41static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t *action)
42{
43 if (action->state.finished)
44 return;
45 action->state.finished = true;
46 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished);
47}
48
49static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action)
50{
51 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset);
52}
53
54bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
55 uint16_t idx = keycode - QK_TAP_DANCE;
56 qk_tap_dance_action_t *action;
57
58 if (last_td && last_td != keycode) {
59 (&tap_dance_actions[last_td - QK_TAP_DANCE])->state.interrupted = true;
60 }
61
62 switch(keycode) {
63 case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
64 if ((int16_t)idx > highest_td)
65 highest_td = idx;
66 action = &tap_dance_actions[idx];
67
68 action->state.pressed = record->event.pressed;
69 if (record->event.pressed) {
70 action->state.keycode = keycode;
71 action->state.count++;
72 action->state.timer = timer_read();
73 process_tap_dance_action_on_each_tap (action);
74
75 if (last_td && last_td != keycode) {
76 qk_tap_dance_action_t *paction = &tap_dance_actions[last_td - QK_TAP_DANCE];
77 paction->state.interrupted = true;
78 process_tap_dance_action_on_dance_finished (paction);
79 reset_tap_dance (&paction->state);
80 }
81
82 last_td = keycode;
83 }
84
85 break;
86
87 default:
88 if (!record->event.pressed)
89 return true;
90
91 if (highest_td == -1)
92 return true;
93
94 for (int i = 0; i <= highest_td; i++) {
95 action = &tap_dance_actions[i];
96 if (action->state.count == 0)
97 continue;
98 action->state.interrupted = true;
99 process_tap_dance_action_on_dance_finished (action);
100 reset_tap_dance (&action->state);
101 }
102 break;
103 }
104
105 return true;
106}
107
108void matrix_scan_tap_dance () {
109 if (highest_td == -1)
110 return;
111
112 for (int i = 0; i <= highest_td; i++) {
113 qk_tap_dance_action_t *action = &tap_dance_actions[i];
114
115 if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) {
116 process_tap_dance_action_on_dance_finished (action);
117 reset_tap_dance (&action->state);
118 }
119 }
120}
121
122void reset_tap_dance (qk_tap_dance_state_t *state) {
123 qk_tap_dance_action_t *action;
124
125 if (state->pressed)
126 return;
127
128 action = &tap_dance_actions[state->keycode - QK_TAP_DANCE];
129
130 process_tap_dance_action_on_reset (action);
131
132 state->count = 0;
133 state->interrupted = false;
134 state->finished = false;
135 last_td = 0;
136}
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
new file mode 100644
index 000000000..f753cbba6
--- /dev/null
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -0,0 +1,72 @@
1#ifndef PROCESS_TAP_DANCE_H
2#define PROCESS_TAP_DANCE_H
3
4#ifdef TAP_DANCE_ENABLE
5
6#include <stdbool.h>
7#include <inttypes.h>
8
9typedef struct
10{
11 uint8_t count;
12 uint16_t keycode;
13 uint16_t timer;
14 bool interrupted;
15 bool pressed;
16 bool finished;
17} qk_tap_dance_state_t;
18
19#define TD(n) (QK_TAP_DANCE + n)
20
21typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state, void *user_data);
22
23typedef struct
24{
25 struct {
26 qk_tap_dance_user_fn_t on_each_tap;
27 qk_tap_dance_user_fn_t on_dance_finished;
28 qk_tap_dance_user_fn_t on_reset;
29 } fn;
30 qk_tap_dance_state_t state;
31 void *user_data;
32} qk_tap_dance_action_t;
33
34typedef struct
35{
36 uint16_t kc1;
37 uint16_t kc2;
38} qk_tap_dance_pair_t;
39
40#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \
41 .fn = { NULL, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset }, \
42 .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }), \
43 }
44
45#define ACTION_TAP_DANCE_FN(user_fn) { \
46 .fn = { NULL, user_fn, NULL }, \
47 .user_data = NULL, \
48 }
49
50#define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset) { \
51 .fn = { user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset }, \
52 .user_data = NULL, \
53 }
54
55extern qk_tap_dance_action_t tap_dance_actions[];
56
57/* To be used internally */
58
59bool process_tap_dance(uint16_t keycode, keyrecord_t *record);
60void matrix_scan_tap_dance (void);
61void reset_tap_dance (qk_tap_dance_state_t *state);
62
63void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data);
64void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data);
65
66#else
67
68#define TD(n) KC_NO
69
70#endif
71
72#endif
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
new file mode 100644
index 000000000..cd3a610b4
--- /dev/null
+++ b/quantum/process_keycode/process_unicode.c
@@ -0,0 +1,264 @@
1#include "process_unicode.h"
2
3static uint8_t input_mode;
4
5__attribute__((weak))
6uint16_t hex_to_keycode(uint8_t hex)
7{
8 if (hex == 0x0) {
9 return KC_0;
10 } else if (hex < 0xA) {
11 return KC_1 + (hex - 0x1);
12 } else {
13 return KC_A + (hex - 0xA);
14 }
15}
16
17void set_unicode_input_mode(uint8_t os_target)
18{
19 input_mode = os_target;
20}
21
22uint8_t get_unicode_input_mode(void) {
23 return input_mode;
24}
25
26__attribute__((weak))
27void unicode_input_start (void) {
28 switch(input_mode) {
29 case UC_OSX:
30 register_code(KC_LALT);
31 break;
32 case UC_LNX:
33 register_code(KC_LCTL);
34 register_code(KC_LSFT);
35 register_code(KC_U);
36 unregister_code(KC_U);
37 unregister_code(KC_LSFT);
38 unregister_code(KC_LCTL);
39 break;
40 case UC_WIN:
41 register_code(KC_LALT);
42 register_code(KC_PPLS);
43 unregister_code(KC_PPLS);
44 break;
45 case UC_WINC:
46 register_code(KC_RALT);
47 unregister_code(KC_RALT);
48 register_code(KC_U);
49 unregister_code(KC_U);
50 }
51 wait_ms(UNICODE_TYPE_DELAY);
52}
53
54__attribute__((weak))
55void unicode_input_finish (void) {
56 switch(input_mode) {
57 case UC_OSX:
58 case UC_WIN:
59 unregister_code(KC_LALT);
60 break;
61 case UC_LNX:
62 register_code(KC_SPC);
63 unregister_code(KC_SPC);
64 break;
65 }
66}
67
68void register_hex(uint16_t hex) {
69 for(int i = 3; i >= 0; i--) {
70 uint8_t digit = ((hex >> (i*4)) & 0xF);
71 register_code(hex_to_keycode(digit));
72 unregister_code(hex_to_keycode(digit));
73 }
74}
75
76bool process_unicode(uint16_t keycode, keyrecord_t *record) {
77 if (keycode > QK_UNICODE && record->event.pressed) {
78 uint16_t unicode = keycode & 0x7FFF;
79 unicode_input_start();
80 register_hex(unicode);
81 unicode_input_finish();
82 }
83 return true;
84}
85
86#ifdef UNICODEMAP_ENABLE
87__attribute__((weak))
88const uint32_t PROGMEM unicode_map[] = {
89};
90
91void register_hex32(uint32_t hex) {
92 uint8_t onzerostart = 1;
93 for(int i = 7; i >= 0; i--) {
94 if (i <= 3) {
95 onzerostart = 0;
96 }
97 uint8_t digit = ((hex >> (i*4)) & 0xF);
98 if (digit == 0) {
99 if (onzerostart == 0) {
100 register_code(hex_to_keycode(digit));
101 unregister_code(hex_to_keycode(digit));
102 }
103 } else {
104 register_code(hex_to_keycode(digit));
105 unregister_code(hex_to_keycode(digit));
106 onzerostart = 0;
107 }
108 }
109}
110
111__attribute__((weak))
112void unicode_map_input_error() {}
113
114bool process_unicode_map(uint16_t keycode, keyrecord_t *record) {
115 if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) {
116 const uint32_t* map = unicode_map;
117 uint16_t index = keycode & 0x7FF;
118 uint32_t code = pgm_read_dword_far(&map[index]);
119 if ((code > 0xFFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
120 // when character is out of range supported by the OS
121 unicode_map_input_error();
122 } else {
123 unicode_input_start();
124 register_hex32(code);
125 unicode_input_finish();
126 }
127 }
128 return true;
129}
130#endif
131
132#ifdef UCIS_ENABLE
133qk_ucis_state_t qk_ucis_state;
134
135void qk_ucis_start(void) {
136 qk_ucis_state.count = 0;
137 qk_ucis_state.in_progress = true;
138
139 qk_ucis_start_user();
140}
141
142__attribute__((weak))
143void qk_ucis_start_user(void) {
144 unicode_input_start();
145 register_hex(0x2328);
146 unicode_input_finish();
147}
148
149static bool is_uni_seq(char *seq) {
150 uint8_t i;
151
152 for (i = 0; seq[i]; i++) {
153 uint16_t code;
154 if (('1' <= seq[i]) && (seq[i] <= '0'))
155 code = seq[i] - '1' + KC_1;
156 else
157 code = seq[i] - 'a' + KC_A;
158
159 if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code)
160 return false;
161 }
162
163 return (qk_ucis_state.codes[i] == KC_ENT ||
164 qk_ucis_state.codes[i] == KC_SPC);
165}
166
167__attribute__((weak))
168void qk_ucis_symbol_fallback (void) {
169 for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) {
170 uint8_t code = qk_ucis_state.codes[i];
171 register_code(code);
172 unregister_code(code);
173 wait_ms(UNICODE_TYPE_DELAY);
174 }
175}
176
177void register_ucis(const char *hex) {
178 for(int i = 0; hex[i]; i++) {
179 uint8_t kc = 0;
180 char c = hex[i];
181
182 switch (c) {
183 case '0':
184 kc = KC_0;
185 break;
186 case '1' ... '9':
187 kc = c - '1' + KC_1;
188 break;
189 case 'a' ... 'f':
190 kc = c - 'a' + KC_A;
191 break;
192 case 'A' ... 'F':
193 kc = c - 'A' + KC_A;
194 break;
195 }
196
197 if (kc) {
198 register_code (kc);
199 unregister_code (kc);
200 wait_ms (UNICODE_TYPE_DELAY);
201 }
202 }
203}
204
205bool process_ucis (uint16_t keycode, keyrecord_t *record) {
206 uint8_t i;
207
208 if (!qk_ucis_state.in_progress)
209 return true;
210
211 if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH &&
212 !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) {
213 return false;
214 }
215
216 if (!record->event.pressed)
217 return true;
218
219 qk_ucis_state.codes[qk_ucis_state.count] = keycode;
220 qk_ucis_state.count++;
221
222 if (keycode == KC_BSPC) {
223 if (qk_ucis_state.count >= 2) {
224 qk_ucis_state.count -= 2;
225 return true;
226 } else {
227 qk_ucis_state.count--;
228 return false;
229 }
230 }
231
232 if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) {
233 bool symbol_found = false;
234
235 for (i = qk_ucis_state.count; i > 0; i--) {
236 register_code (KC_BSPC);
237 unregister_code (KC_BSPC);
238 wait_ms(UNICODE_TYPE_DELAY);
239 }
240
241 if (keycode == KC_ESC) {
242 qk_ucis_state.in_progress = false;
243 return false;
244 }
245
246 unicode_input_start();
247 for (i = 0; ucis_symbol_table[i].symbol; i++) {
248 if (is_uni_seq (ucis_symbol_table[i].symbol)) {
249 symbol_found = true;
250 register_ucis(ucis_symbol_table[i].code + 2);
251 break;
252 }
253 }
254 if (!symbol_found) {
255 qk_ucis_symbol_fallback();
256 }
257 unicode_input_finish();
258
259 qk_ucis_state.in_progress = false;
260 return false;
261 }
262 return true;
263}
264#endif
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h
new file mode 100644
index 000000000..065eeb5f6
--- /dev/null
+++ b/quantum/process_keycode/process_unicode.h
@@ -0,0 +1,166 @@
1#ifndef PROCESS_UNICODE_H
2#define PROCESS_UNICODE_H
3
4#include "quantum.h"
5
6#define UC_OSX 0 // Mac OS X
7#define UC_LNX 1 // Linux
8#define UC_WIN 2 // Windows 'HexNumpad'
9#define UC_BSD 3 // BSD (not implemented)
10#define UC_WINC 4 // WinCompose https://github.com/samhocevar/wincompose
11
12#ifndef UNICODE_TYPE_DELAY
13#define UNICODE_TYPE_DELAY 10
14#endif
15
16void set_unicode_input_mode(uint8_t os_target);
17uint8_t get_unicode_input_mode(void);
18void unicode_input_start(void);
19void unicode_input_finish(void);
20void register_hex(uint16_t hex);
21
22bool process_unicode(uint16_t keycode, keyrecord_t *record);
23
24#ifdef UNICODEMAP_ENABLE
25bool process_unicode_map(uint16_t keycode, keyrecord_t *record);
26#endif
27
28#ifdef UCIS_ENABLE
29#ifndef UCIS_MAX_SYMBOL_LENGTH
30#define UCIS_MAX_SYMBOL_LENGTH 32
31#endif
32
33typedef struct {
34 char *symbol;
35 char *code;
36} qk_ucis_symbol_t;
37
38typedef struct {
39 uint8_t count;
40 uint16_t codes[UCIS_MAX_SYMBOL_LENGTH];
41 bool in_progress:1;
42} qk_ucis_state_t;
43
44extern qk_ucis_state_t qk_ucis_state;
45
46#define UCIS_TABLE(...) {__VA_ARGS__, {NULL, NULL}}
47#define UCIS_SYM(name, code) {name, #code}
48
49extern const qk_ucis_symbol_t ucis_symbol_table[];
50
51void qk_ucis_start(void);
52void qk_ucis_start_user(void);
53void qk_ucis_symbol_fallback (void);
54void register_ucis(const char *hex);
55bool process_ucis (uint16_t keycode, keyrecord_t *record);
56
57#endif
58
59#define UC_BSPC UC(0x0008)
60
61#define UC_SPC UC(0x0020)
62
63#define UC_EXLM UC(0x0021)
64#define UC_DQUT UC(0x0022)
65#define UC_HASH UC(0x0023)
66#define UC_DLR UC(0x0024)
67#define UC_PERC UC(0x0025)
68#define UC_AMPR UC(0x0026)
69#define UC_QUOT UC(0x0027)
70#define UC_LPRN UC(0x0028)
71#define UC_RPRN UC(0x0029)
72#define UC_ASTR UC(0x002A)
73#define UC_PLUS UC(0x002B)
74#define UC_COMM UC(0x002C)
75#define UC_DASH UC(0x002D)
76#define UC_DOT UC(0x002E)
77#define UC_SLSH UC(0x002F)
78
79#define UC_0 UC(0x0030)
80#define UC_1 UC(0x0031)
81#define UC_2 UC(0x0032)
82#define UC_3 UC(0x0033)
83#define UC_4 UC(0x0034)
84#define UC_5 UC(0x0035)
85#define UC_6 UC(0x0036)
86#define UC_7 UC(0x0037)
87#define UC_8 UC(0x0038)
88#define UC_9 UC(0x0039)
89
90#define UC_COLN UC(0x003A)
91#define UC_SCLN UC(0x003B)
92#define UC_LT UC(0x003C)
93#define UC_EQL UC(0x003D)
94#define UC_GT UC(0x003E)
95#define UC_QUES UC(0x003F)
96#define UC_AT UC(0x0040)
97
98#define UC_A UC(0x0041)
99#define UC_B UC(0x0042)
100#define UC_C UC(0x0043)
101#define UC_D UC(0x0044)
102#define UC_E UC(0x0045)
103#define UC_F UC(0x0046)
104#define UC_G UC(0x0047)
105#define UC_H UC(0x0048)
106#define UC_I UC(0x0049)
107#define UC_J UC(0x004A)
108#define UC_K UC(0x004B)
109#define UC_L UC(0x004C)
110#define UC_M UC(0x004D)
111#define UC_N UC(0x004E)
112#define UC_O UC(0x004F)
113#define UC_P UC(0x0050)
114#define UC_Q UC(0x0051)
115#define UC_R UC(0x0052)
116#define UC_S UC(0x0053)
117#define UC_T UC(0x0054)
118#define UC_U UC(0x0055)
119#define UC_V UC(0x0056)
120#define UC_W UC(0x0057)
121#define UC_X UC(0x0058)
122#define UC_Y UC(0x0059)
123#define UC_Z UC(0x005A)
124
125#define UC_LBRC UC(0x005B)
126#define UC_BSLS UC(0x005C)
127#define UC_RBRC UC(0x005D)
128#define UC_CIRM UC(0x005E)
129#define UC_UNDR UC(0x005F)
130
131#define UC_GRV UC(0x0060)
132
133#define UC_a UC(0x0061)
134#define UC_b UC(0x0062)
135#define UC_c UC(0x0063)
136#define UC_d UC(0x0064)
137#define UC_e UC(0x0065)
138#define UC_f UC(0x0066)
139#define UC_g UC(0x0067)
140#define UC_h UC(0x0068)
141#define UC_i UC(0x0069)
142#define UC_j UC(0x006A)
143#define UC_k UC(0x006B)
144#define UC_l UC(0x006C)
145#define UC_m UC(0x006D)
146#define UC_n UC(0x006E)
147#define UC_o UC(0x006F)
148#define UC_p UC(0x0070)
149#define UC_q UC(0x0071)
150#define UC_r UC(0x0072)
151#define UC_s UC(0x0073)
152#define UC_t UC(0x0074)
153#define UC_u UC(0x0075)
154#define UC_v UC(0x0076)
155#define UC_w UC(0x0077)
156#define UC_x UC(0x0078)
157#define UC_y UC(0x0079)
158#define UC_z UC(0x007A)
159
160#define UC_LCBR UC(0x007B)
161#define UC_PIPE UC(0x007C)
162#define UC_RCBR UC(0x007D)
163#define UC_TILD UC(0x007E)
164#define UC_DEL UC(0x007F)
165
166#endif
diff --git a/quantum/quantum.c b/quantum/quantum.c
new file mode 100644
index 000000000..098312e6e
--- /dev/null
+++ b/quantum/quantum.c
@@ -0,0 +1,853 @@
1#include "quantum.h"
2
3static void do_code16 (uint16_t code, void (*f) (uint8_t)) {
4 switch (code) {
5 case QK_MODS ... QK_MODS_MAX:
6 break;
7 default:
8 return;
9 }
10
11 if (code & QK_LCTL)
12 f(KC_LCTL);
13 if (code & QK_LSFT)
14 f(KC_LSFT);
15 if (code & QK_LALT)
16 f(KC_LALT);
17 if (code & QK_LGUI)
18 f(KC_LGUI);
19
20 if (code & QK_RCTL)
21 f(KC_RCTL);
22 if (code & QK_RSFT)
23 f(KC_RSFT);
24 if (code & QK_RALT)
25 f(KC_RALT);
26 if (code & QK_RGUI)
27 f(KC_RGUI);
28}
29
30void register_code16 (uint16_t code) {
31 do_code16 (code, register_code);
32 register_code (code);
33}
34
35void unregister_code16 (uint16_t code) {
36 unregister_code (code);
37 do_code16 (code, unregister_code);
38}
39
40__attribute__ ((weak))
41bool process_action_kb(keyrecord_t *record) {
42 return true;
43}
44
45__attribute__ ((weak))
46bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
47 return process_record_user(keycode, record);
48}
49
50__attribute__ ((weak))
51bool process_record_user(uint16_t keycode, keyrecord_t *record) {
52 return true;
53}
54
55void reset_keyboard(void) {
56 clear_keyboard();
57#ifdef AUDIO_ENABLE
58 stop_all_notes();
59 shutdown_user();
60#endif
61 wait_ms(250);
62#ifdef CATERINA_BOOTLOADER
63 *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific
64#endif
65 bootloader_jump();
66}
67
68// Shift / paren setup
69
70#ifndef LSPO_KEY
71 #define LSPO_KEY KC_9
72#endif
73#ifndef RSPC_KEY
74 #define RSPC_KEY KC_0
75#endif
76
77static bool shift_interrupted[2] = {0, 0};
78
79bool process_record_quantum(keyrecord_t *record) {
80
81 /* This gets the keycode from the key pressed */
82 keypos_t key = record->event.key;
83 uint16_t keycode;
84
85 #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
86 /* TODO: Use store_or_get_action() or a similar function. */
87 if (!disable_action_cache) {
88 uint8_t layer;
89
90 if (record->event.pressed) {
91 layer = layer_switch_get_layer(key);
92 update_source_layers_cache(key, layer);
93 } else {
94 layer = read_source_layers_cache(key);
95 }
96 keycode = keymap_key_to_keycode(layer, key);
97 } else
98 #endif
99 keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
100
101 // This is how you use actions here
102 // if (keycode == KC_LEAD) {
103 // action_t action;
104 // action.code = ACTION_DEFAULT_LAYER_SET(0);
105 // process_action(record, action);
106 // return false;
107 // }
108
109 if (!(
110 process_record_kb(keycode, record) &&
111 #ifdef MIDI_ENABLE
112 process_midi(keycode, record) &&
113 #endif
114 #ifdef AUDIO_ENABLE
115 process_music(keycode, record) &&
116 #endif
117 #ifdef TAP_DANCE_ENABLE
118 process_tap_dance(keycode, record) &&
119 #endif
120 #ifndef DISABLE_LEADER
121 process_leader(keycode, record) &&
122 #endif
123 #ifndef DISABLE_CHORDING
124 process_chording(keycode, record) &&
125 #endif
126 #ifdef UNICODE_ENABLE
127 process_unicode(keycode, record) &&
128 #endif
129 #ifdef UCIS_ENABLE
130 process_ucis(keycode, record) &&
131 #endif
132 #ifdef UNICODEMAP_ENABLE
133 process_unicode_map(keycode, record) &&
134 #endif
135 true)) {
136 return false;
137 }
138
139 // Shift / paren setup
140
141 switch(keycode) {
142 case RESET:
143 if (record->event.pressed) {
144 reset_keyboard();
145 }
146 return false;
147 break;
148 case DEBUG:
149 if (record->event.pressed) {
150 print("\nDEBUG: enabled.\n");
151 debug_enable = true;
152 }
153 return false;
154 break;
155 #ifdef RGBLIGHT_ENABLE
156 case RGB_TOG:
157 if (record->event.pressed) {
158 rgblight_toggle();
159 }
160 return false;
161 break;
162 case RGB_MOD:
163 if (record->event.pressed) {
164 rgblight_step();
165 }
166 return false;
167 break;
168 case RGB_HUI:
169 if (record->event.pressed) {
170 rgblight_increase_hue();
171 }
172 return false;
173 break;
174 case RGB_HUD:
175 if (record->event.pressed) {
176 rgblight_decrease_hue();
177 }
178 return false;
179 break;
180 case RGB_SAI:
181 if (record->event.pressed) {
182 rgblight_increase_sat();
183 }
184 return false;
185 break;
186 case RGB_SAD:
187 if (record->event.pressed) {
188 rgblight_decrease_sat();
189 }
190 return false;
191 break;
192 case RGB_VAI:
193 if (record->event.pressed) {
194 rgblight_increase_val();
195 }
196 return false;
197 break;
198 case RGB_VAD:
199 if (record->event.pressed) {
200 rgblight_decrease_val();
201 }
202 return false;
203 break;
204 #endif
205 case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_NKRO:
206 if (record->event.pressed) {
207 // MAGIC actions (BOOTMAGIC without the boot)
208 if (!eeconfig_is_enabled()) {
209 eeconfig_init();
210 }
211 /* keymap config */
212 keymap_config.raw = eeconfig_read_keymap();
213 switch (keycode)
214 {
215 case MAGIC_SWAP_CONTROL_CAPSLOCK:
216 keymap_config.swap_control_capslock = true;
217 break;
218 case MAGIC_CAPSLOCK_TO_CONTROL:
219 keymap_config.capslock_to_control = true;
220 break;
221 case MAGIC_SWAP_LALT_LGUI:
222 keymap_config.swap_lalt_lgui = true;
223 break;
224 case MAGIC_SWAP_RALT_RGUI:
225 keymap_config.swap_ralt_rgui = true;
226 break;
227 case MAGIC_NO_GUI:
228 keymap_config.no_gui = true;
229 break;
230 case MAGIC_SWAP_GRAVE_ESC:
231 keymap_config.swap_grave_esc = true;
232 break;
233 case MAGIC_SWAP_BACKSLASH_BACKSPACE:
234 keymap_config.swap_backslash_backspace = true;
235 break;
236 case MAGIC_HOST_NKRO:
237 keymap_config.nkro = true;
238 break;
239 case MAGIC_SWAP_ALT_GUI:
240 keymap_config.swap_lalt_lgui = true;
241 keymap_config.swap_ralt_rgui = true;
242 break;
243 case MAGIC_UNSWAP_CONTROL_CAPSLOCK:
244 keymap_config.swap_control_capslock = false;
245 break;
246 case MAGIC_UNCAPSLOCK_TO_CONTROL:
247 keymap_config.capslock_to_control = false;
248 break;
249 case MAGIC_UNSWAP_LALT_LGUI:
250 keymap_config.swap_lalt_lgui = false;
251 break;
252 case MAGIC_UNSWAP_RALT_RGUI:
253 keymap_config.swap_ralt_rgui = false;
254 break;
255 case MAGIC_UNNO_GUI:
256 keymap_config.no_gui = false;
257 break;
258 case MAGIC_UNSWAP_GRAVE_ESC:
259 keymap_config.swap_grave_esc = false;
260 break;
261 case MAGIC_UNSWAP_BACKSLASH_BACKSPACE:
262 keymap_config.swap_backslash_backspace = false;
263 break;
264 case MAGIC_UNHOST_NKRO:
265 keymap_config.nkro = false;
266 break;
267 case MAGIC_UNSWAP_ALT_GUI:
268 keymap_config.swap_lalt_lgui = false;
269 keymap_config.swap_ralt_rgui = false;
270 break;
271 case MAGIC_TOGGLE_NKRO:
272 keymap_config.nkro = !keymap_config.nkro;
273 break;
274 default:
275 break;
276 }
277 eeconfig_update_keymap(keymap_config.raw);
278 clear_keyboard(); // clear to prevent stuck keys
279
280 return false;
281 }
282 break;
283 case KC_LSPO: {
284 if (record->event.pressed) {
285 shift_interrupted[0] = false;
286 register_mods(MOD_BIT(KC_LSFT));
287 }
288 else {
289 #ifdef DISABLE_SPACE_CADET_ROLLOVER
290 if (get_mods() & MOD_BIT(KC_RSFT)) {
291 shift_interrupted[0] = true;
292 shift_interrupted[1] = true;
293 }
294 #endif
295 if (!shift_interrupted[0]) {
296 register_code(LSPO_KEY);
297 unregister_code(LSPO_KEY);
298 }
299 unregister_mods(MOD_BIT(KC_LSFT));
300 }
301 return false;
302 // break;
303 }
304
305 case KC_RSPC: {
306 if (record->event.pressed) {
307 shift_interrupted[1] = false;
308 register_mods(MOD_BIT(KC_RSFT));
309 }
310 else {
311 #ifdef DISABLE_SPACE_CADET_ROLLOVER
312 if (get_mods() & MOD_BIT(KC_LSFT)) {
313 shift_interrupted[0] = true;
314 shift_interrupted[1] = true;
315 }
316 #endif
317 if (!shift_interrupted[1]) {
318 register_code(RSPC_KEY);
319 unregister_code(RSPC_KEY);
320 }
321 unregister_mods(MOD_BIT(KC_RSFT));
322 }
323 return false;
324 // break;
325 }
326 default: {
327 shift_interrupted[0] = true;
328 shift_interrupted[1] = true;
329 break;
330 }
331 }
332
333 return process_action_kb(record);
334}
335
336const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
337 0, 0, 0, 0, 0, 0, 0, 0,
338 0, 0, 0, 0, 0, 0, 0, 0,
339 0, 0, 0, 0, 0, 0, 0, 0,
340 0, 0, 0, 0, 0, 0, 0, 0,
341 0, 1, 1, 1, 1, 1, 1, 0,
342 1, 1, 1, 1, 0, 0, 0, 0,
343 0, 0, 0, 0, 0, 0, 0, 0,
344 0, 0, 1, 0, 1, 0, 1, 1,
345 1, 1, 1, 1, 1, 1, 1, 1,
346 1, 1, 1, 1, 1, 1, 1, 1,
347 1, 1, 1, 1, 1, 1, 1, 1,
348 1, 1, 1, 0, 0, 0, 1, 1,
349 0, 0, 0, 0, 0, 0, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 0, 1, 1, 1, 1, 0
353};
354
355const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
356 0, 0, 0, 0, 0, 0, 0, 0,
357 KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
358 0, 0, 0, 0, 0, 0, 0, 0,
359 0, 0, 0, KC_ESC, 0, 0, 0, 0,
360 KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
361 KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
362 KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
363 KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
364 KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
365 KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
366 KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
367 KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
368 KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
369 KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
370 KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
371 KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
372};
373
374/* for users whose OSes are set to Colemak */
375#if 0
376#include "keymap_colemak.h"
377
378const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = {
379 0, 0, 0, 0, 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0,
382 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 1, 1, 1, 1, 1, 1, 0,
384 1, 1, 1, 1, 0, 0, 0, 0,
385 0, 0, 0, 0, 0, 0, 0, 0,
386 0, 0, 1, 0, 1, 0, 1, 1,
387 1, 1, 1, 1, 1, 1, 1, 1,
388 1, 1, 1, 1, 1, 1, 1, 1,
389 1, 1, 1, 1, 1, 1, 1, 1,
390 1, 1, 1, 0, 0, 0, 1, 1,
391 0, 0, 0, 0, 0, 0, 0, 0,
392 0, 0, 0, 0, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0,
394 0, 0, 0, 1, 1, 1, 1, 0
395};
396
397const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = {
398 0, 0, 0, 0, 0, 0, 0, 0,
399 KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
400 0, 0, 0, 0, 0, 0, 0, 0,
401 0, 0, 0, KC_ESC, 0, 0, 0, 0,
402 KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
403 KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
404 KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
405 KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
406 KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
407 CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
408 CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
409 CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
410 KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
411 CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
412 CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
413 CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
414};
415
416#endif
417
418void send_string(const char *str) {
419 while (1) {
420 uint8_t keycode;
421 uint8_t ascii_code = pgm_read_byte(str);
422 if (!ascii_code) break;
423 keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]);
424 if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) {
425 register_code(KC_LSFT);
426 register_code(keycode);
427 unregister_code(keycode);
428 unregister_code(KC_LSFT);
429 }
430 else {
431 register_code(keycode);
432 unregister_code(keycode);
433 }
434 ++str;
435 }
436}
437
438void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
439 if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) {
440 layer_on(layer3);
441 } else {
442 layer_off(layer3);
443 }
444}
445
446void tap_random_base64(void) {
447 #if defined(__AVR_ATmega32U4__)
448 uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64;
449 #else
450 uint8_t key = rand() % 64;
451 #endif
452 switch (key) {
453 case 0 ... 25:
454 register_code(KC_LSFT);
455 register_code(key + KC_A);
456 unregister_code(key + KC_A);
457 unregister_code(KC_LSFT);
458 break;
459 case 26 ... 51:
460 register_code(key - 26 + KC_A);
461 unregister_code(key - 26 + KC_A);
462 break;
463 case 52:
464 register_code(KC_0);
465 unregister_code(KC_0);
466 break;
467 case 53 ... 61:
468 register_code(key - 53 + KC_1);
469 unregister_code(key - 53 + KC_1);
470 break;
471 case 62:
472 register_code(KC_LSFT);
473 register_code(KC_EQL);
474 unregister_code(KC_EQL);
475 unregister_code(KC_LSFT);
476 break;
477 case 63:
478 register_code(KC_SLSH);
479 unregister_code(KC_SLSH);
480 break;
481 }
482}
483
484void matrix_init_quantum() {
485 #ifdef BACKLIGHT_ENABLE
486 backlight_init_ports();
487 #endif
488 matrix_init_kb();
489}
490
491void matrix_scan_quantum() {
492 #ifdef AUDIO_ENABLE
493 matrix_scan_music();
494 #endif
495
496 #ifdef TAP_DANCE_ENABLE
497 matrix_scan_tap_dance();
498 #endif
499 matrix_scan_kb();
500}
501
502#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
503
504static const uint8_t backlight_pin = BACKLIGHT_PIN;
505
506#if BACKLIGHT_PIN == B7
507# define COM1x1 COM1C1
508# define OCR1x OCR1C
509#elif BACKLIGHT_PIN == B6
510# define COM1x1 COM1B1
511# define OCR1x OCR1B
512#elif BACKLIGHT_PIN == B5
513# define COM1x1 COM1A1
514# define OCR1x OCR1A
515#else
516# error "Backlight pin not supported - use B5, B6, or B7"
517#endif
518
519__attribute__ ((weak))
520void backlight_init_ports(void)
521{
522
523 // Setup backlight pin as output and output low.
524 // DDRx |= n
525 _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
526 // PORTx &= ~n
527 _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
528
529 // Use full 16-bit resolution.
530 ICR1 = 0xFFFF;
531
532 // I could write a wall of text here to explain... but TL;DW
533 // Go read the ATmega32u4 datasheet.
534 // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
535
536 // Pin PB7 = OCR1C (Timer 1, Channel C)
537 // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
538 // (i.e. start high, go low when counter matches.)
539 // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
540 // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
541
542 TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010;
543 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
544
545 backlight_init();
546 #ifdef BACKLIGHT_BREATHING
547 breathing_defaults();
548 #endif
549}
550
551__attribute__ ((weak))
552void backlight_set(uint8_t level)
553{
554 // Prevent backlight blink on lowest level
555 // PORTx &= ~n
556 _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
557
558 if ( level == 0 ) {
559 // Turn off PWM control on backlight pin, revert to output low.
560 TCCR1A &= ~(_BV(COM1x1));
561 OCR1x = 0x0;
562 } else if ( level == BACKLIGHT_LEVELS ) {
563 // Turn on PWM control of backlight pin
564 TCCR1A |= _BV(COM1x1);
565 // Set the brightness
566 OCR1x = 0xFFFF;
567 } else {
568 // Turn on PWM control of backlight pin
569 TCCR1A |= _BV(COM1x1);
570 // Set the brightness
571 OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
572 }
573
574 #ifdef BACKLIGHT_BREATHING
575 breathing_intensity_default();
576 #endif
577}
578
579
580#ifdef BACKLIGHT_BREATHING
581
582#define BREATHING_NO_HALT 0
583#define BREATHING_HALT_OFF 1
584#define BREATHING_HALT_ON 2
585
586static uint8_t breath_intensity;
587static uint8_t breath_speed;
588static uint16_t breathing_index;
589static uint8_t breathing_halt;
590
591void breathing_enable(void)
592{
593 if (get_backlight_level() == 0)
594 {
595 breathing_index = 0;
596 }
597 else
598 {
599 // Set breathing_index to be at the midpoint (brightest point)
600 breathing_index = 0x20 << breath_speed;
601 }
602
603 breathing_halt = BREATHING_NO_HALT;
604
605 // Enable breathing interrupt
606 TIMSK1 |= _BV(OCIE1A);
607}
608
609void breathing_pulse(void)
610{
611 if (get_backlight_level() == 0)
612 {
613 breathing_index = 0;
614 }
615 else
616 {
617 // Set breathing_index to be at the midpoint + 1 (brightest point)
618 breathing_index = 0x21 << breath_speed;
619 }
620
621 breathing_halt = BREATHING_HALT_ON;
622
623 // Enable breathing interrupt
624 TIMSK1 |= _BV(OCIE1A);
625}
626
627void breathing_disable(void)
628{
629 // Disable breathing interrupt
630 TIMSK1 &= ~_BV(OCIE1A);
631 backlight_set(get_backlight_level());
632}
633
634void breathing_self_disable(void)
635{
636 if (get_backlight_level() == 0)
637 {
638 breathing_halt = BREATHING_HALT_OFF;
639 }
640 else
641 {
642 breathing_halt = BREATHING_HALT_ON;
643 }
644
645 //backlight_set(get_backlight_level());
646}
647
648void breathing_toggle(void)
649{
650 if (!is_breathing())
651 {
652 if (get_backlight_level() == 0)
653 {
654 breathing_index = 0;
655 }
656 else
657 {
658 // Set breathing_index to be at the midpoint + 1 (brightest point)
659 breathing_index = 0x21 << breath_speed;
660 }
661
662 breathing_halt = BREATHING_NO_HALT;
663 }
664
665 // Toggle breathing interrupt
666 TIMSK1 ^= _BV(OCIE1A);
667
668 // Restore backlight level
669 if (!is_breathing())
670 {
671 backlight_set(get_backlight_level());
672 }
673}
674
675bool is_breathing(void)
676{
677 return (TIMSK1 && _BV(OCIE1A));
678}
679
680void breathing_intensity_default(void)
681{
682 //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
683 breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
684}
685
686void breathing_intensity_set(uint8_t value)
687{
688 breath_intensity = value;
689}
690
691void breathing_speed_default(void)
692{
693 breath_speed = 4;
694}
695
696void breathing_speed_set(uint8_t value)
697{
698 bool is_breathing_now = is_breathing();
699 uint8_t old_breath_speed = breath_speed;
700
701 if (is_breathing_now)
702 {
703 // Disable breathing interrupt
704 TIMSK1 &= ~_BV(OCIE1A);
705 }
706
707 breath_speed = value;
708
709 if (is_breathing_now)
710 {
711 // Adjust index to account for new speed
712 breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
713
714 // Enable breathing interrupt
715 TIMSK1 |= _BV(OCIE1A);
716 }
717
718}
719
720void breathing_speed_inc(uint8_t value)
721{
722 if ((uint16_t)(breath_speed - value) > 10 )
723 {
724 breathing_speed_set(0);
725 }
726 else
727 {
728 breathing_speed_set(breath_speed - value);
729 }
730}
731
732void breathing_speed_dec(uint8_t value)
733{
734 if ((uint16_t)(breath_speed + value) > 10 )
735 {
736 breathing_speed_set(10);
737 }
738 else
739 {
740 breathing_speed_set(breath_speed + value);
741 }
742}
743
744void breathing_defaults(void)
745{
746 breathing_intensity_default();
747 breathing_speed_default();
748 breathing_halt = BREATHING_NO_HALT;
749}
750
751/* Breathing Sleep LED brighness(PWM On period) table
752 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
753 *
754 * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
755 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
756 */
757static const uint8_t breathing_table[64] PROGMEM = {
758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
759 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
760255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
761 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
762};
763
764ISR(TIMER1_COMPA_vect)
765{
766 // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
767
768
769 uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
770
771 if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
772 {
773 // Disable breathing interrupt
774 TIMSK1 &= ~_BV(OCIE1A);
775 }
776
777 OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;
778
779}
780
781
782
783#endif // breathing
784
785#else // backlight
786
787__attribute__ ((weak))
788void backlight_init_ports(void)
789{
790
791}
792
793__attribute__ ((weak))
794void backlight_set(uint8_t level)
795{
796
797}
798
799#endif // backlight
800
801
802
803__attribute__ ((weak))
804void led_set_user(uint8_t usb_led) {
805
806}
807
808__attribute__ ((weak))
809void led_set_kb(uint8_t usb_led) {
810 led_set_user(usb_led);
811}
812
813__attribute__ ((weak))
814void led_init_ports(void)
815{
816
817}
818
819__attribute__ ((weak))
820void led_set(uint8_t usb_led)
821{
822
823 // Example LED Code
824 //
825 // // Using PE6 Caps Lock LED
826 // if (usb_led & (1<<USB_LED_CAPS_LOCK))
827 // {
828 // // Output high.
829 // DDRE |= (1<<6);
830 // PORTE |= (1<<6);
831 // }
832 // else
833 // {
834 // // Output low.
835 // DDRE &= ~(1<<6);
836 // PORTE &= ~(1<<6);
837 // }
838
839 led_set_kb(usb_led);
840}
841
842
843//------------------------------------------------------------------------------
844// Override these functions in your keymap file to play different tunes on
845// different events such as startup and bootloader jump
846
847__attribute__ ((weak))
848void startup_user() {}
849
850__attribute__ ((weak))
851void shutdown_user() {}
852
853//------------------------------------------------------------------------------
diff --git a/quantum/quantum.h b/quantum/quantum.h
new file mode 100644
index 000000000..0c6046649
--- /dev/null
+++ b/quantum/quantum.h
@@ -0,0 +1,113 @@
1#ifndef QUANTUM_H
2#define QUANTUM_H
3
4#if defined(__AVR__)
5#include <avr/pgmspace.h>
6#include <avr/io.h>
7#include <avr/interrupt.h>
8#endif
9#include "wait.h"
10#include "matrix.h"
11#include "keymap.h"
12#ifdef BACKLIGHT_ENABLE
13 #include "backlight.h"
14#endif
15#ifdef RGBLIGHT_ENABLE
16 #include "rgblight.h"
17#endif
18
19#include "action_layer.h"
20#include "eeconfig.h"
21#include <stddef.h>
22#include "bootloader.h"
23#include "timer.h"
24#include "config_common.h"
25#include "led.h"
26#include "action_util.h"
27#include <stdlib.h>
28#include "print.h"
29
30
31extern uint32_t default_layer_state;
32
33#ifndef NO_ACTION_LAYER
34 extern uint32_t layer_state;
35#endif
36
37#ifdef MIDI_ENABLE
38 #include <lufa.h>
39 #include "process_midi.h"
40#endif
41
42#ifdef AUDIO_ENABLE
43 #include "audio.h"
44 #include "process_music.h"
45#endif
46
47#ifndef DISABLE_LEADER
48 #include "process_leader.h"
49#endif
50
51#define DISABLE_CHORDING
52#ifndef DISABLE_CHORDING
53 #include "process_chording.h"
54#endif
55
56#ifdef UNICODE_ENABLE
57 #include "process_unicode.h"
58#endif
59
60#include "process_tap_dance.h"
61
62#define SEND_STRING(str) send_string(PSTR(str))
63void send_string(const char *str);
64
65// For tri-layer
66void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
67
68void tap_random_base64(void);
69
70#define IS_LAYER_ON(layer) (layer_state & (1UL << (layer)))
71#define IS_LAYER_OFF(layer) (~layer_state & (1UL << (layer)))
72
73void matrix_init_kb(void);
74void matrix_scan_kb(void);
75void matrix_init_user(void);
76void matrix_scan_user(void);
77bool process_action_kb(keyrecord_t *record);
78bool process_record_kb(uint16_t keycode, keyrecord_t *record);
79bool process_record_user(uint16_t keycode, keyrecord_t *record);
80
81void reset_keyboard(void);
82
83void startup_user(void);
84void shutdown_user(void);
85
86void register_code16 (uint16_t code);
87void unregister_code16 (uint16_t code);
88
89#ifdef BACKLIGHT_ENABLE
90void backlight_init_ports(void);
91
92#ifdef BACKLIGHT_BREATHING
93void breathing_enable(void);
94void breathing_pulse(void);
95void breathing_disable(void);
96void breathing_self_disable(void);
97void breathing_toggle(void);
98bool is_breathing(void);
99
100void breathing_defaults(void);
101void breathing_intensity_default(void);
102void breathing_speed_default(void);
103void breathing_speed_set(uint8_t value);
104void breathing_speed_inc(uint8_t value);
105void breathing_speed_dec(uint8_t value);
106#endif
107
108#endif
109
110void led_set_user(uint8_t usb_led);
111void led_set_kb(uint8_t usb_led);
112
113#endif
diff --git a/quantum/quantum.mk b/quantum/quantum.mk
deleted file mode 100644
index de93af7e8..000000000
--- a/quantum/quantum.mk
+++ /dev/null
@@ -1,53 +0,0 @@
1QUANTUM_DIR = quantum
2
3# # project specific files
4SRC += $(QUANTUM_DIR)/keymap_common.c \
5 $(QUANTUM_DIR)/led.c
6
7# ifdef KEYMAP_FILE
8# ifneq (,$(shell grep USING_MIDI '$(KEYMAP_FILE)'))
9# MIDI_ENABLE=yes
10# $(info * Overriding MIDI_ENABLE setting - $(KEYMAP_FILE) requires it)
11# endif
12# ifneq (,$(shell grep USING_UNICODE '$(KEYMAP_FILE)'))
13# UNICODE_ENABLE=yes
14# $(info * Overriding UNICODE_ENABLE setting - $(KEYMAP_FILE) requires it)
15# endif
16# ifneq (,$(shell grep USING_BACKLIGHT '$(KEYMAP_FILE)'))
17# BACKLIGHT_ENABLE=yes
18# $(info * Overriding BACKLIGHT_ENABLE setting - $(KEYMAP_FILE) requires it)
19# endif
20# endif
21
22ifndef CUSTOM_MATRIX
23 SRC += $(QUANTUM_DIR)/matrix.c
24endif
25
26ifdef MIDI_ENABLE
27 SRC += $(QUANTUM_DIR)/keymap_midi.c
28endif
29
30ifdef AUDIO_ENABLE
31 SRC += $(QUANTUM_DIR)/audio.c
32endif
33
34ifdef UNICODE_ENABLE
35 SRC += $(QUANTUM_DIR)/keymap_unicode.c
36endif
37
38ifdef RGBLIGHT_ENABLE
39 SRC += $(QUANTUM_DIR)/light_ws2812.c
40 SRC += $(QUANTUM_DIR)/rgblight.c
41 OPT_DEFS += -DRGBLIGHT_ENABLE
42endif
43
44# Optimize size but this may cause error "relocation truncated to fit"
45#EXTRALDFLAGS = -Wl,--relax
46
47# Search Path
48VPATH += $(TOP_DIR)/$(QUANTUM_DIR)
49
50include $(TMK_DIR)/protocol/lufa.mk
51
52include $(TMK_DIR)/common.mk
53include $(TMK_DIR)/rules.mk
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index 2215cf5cd..d550c5866 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -6,29 +6,65 @@
6#include "rgblight.h" 6#include "rgblight.h"
7#include "debug.h" 7#include "debug.h"
8 8
9// Lightness curve using the CIE 1931 lightness formula
10//Generated by the python script provided in http://jared.geek.nz/2013/feb/linear-led-pwm
9const uint8_t DIM_CURVE[] PROGMEM = { 11const uint8_t DIM_CURVE[] PROGMEM = {
10 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 12 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
11 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 13 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
12 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 14 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
13 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 15 3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
14 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 16 5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
15 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 17 7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
16 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 18 10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
17 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 19 13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
18 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, 20 17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
19 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 21 22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
20 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 22 28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
21 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 23 34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
22 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 24 41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
23 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 25 49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
24 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 26 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
25 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, 27 68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
28 80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
29 92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
30 106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
31 121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
32 138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
33 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
34 175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
35 196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
36 218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
37 242, 245, 247, 250, 252, 255,
38 };
39
40const uint8_t RGBLED_BREATHING_TABLE[] PROGMEM = {
41 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9,
42 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
43 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
44 79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124,
45 127, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, 173,
46 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, 213, 215,
47 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241, 243, 244,
48 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
49 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, 248, 246,
50 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220,
51 218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179,
52 176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, 134, 131,
53 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 93, 90, 88, 85, 82,
54 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40,
55 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11,
56 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0
26}; 57};
27const uint8_t RGBLED_BREATHING_TABLE[] PROGMEM = {0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124,127,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0}; 58
59__attribute__ ((weak))
28const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; 60const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
61__attribute__ ((weak))
29const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; 62const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
63__attribute__ ((weak))
30const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; 64const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
65__attribute__ ((weak))
31const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; 66const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
67__attribute__ ((weak))
32const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; 68const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20};
33 69
34rgblight_config_t rgblight_config; 70rgblight_config_t rgblight_config;
@@ -38,63 +74,54 @@ uint8_t rgblight_inited = 0;
38 74
39 75
40void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) { 76void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) {
41 /* convert hue, saturation and brightness ( HSB/HSV ) to RGB 77 uint8_t r = 0, g = 0, b = 0, base, color;
42 The DIM_CURVE is used only on brightness/value and on saturation (inverted). 78
43 This looks the most natural. 79 if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
44 */ 80 r = val;
45 uint8_t r, g, b; 81 g = val;
46 82 b = val;
47 val = pgm_read_byte(&DIM_CURVE[val]); 83 } else {
48 sat = 255 - pgm_read_byte(&DIM_CURVE[255 - sat]); 84 base = ((255 - sat) * val) >> 8;
49 85 color = (val - base) * (hue % 60) / 60;
50 uint8_t base; 86
51 87 switch (hue / 60) {
52 if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. 88 case 0:
53 r = val; 89 r = val;
54 g = val; 90 g = base + color;
55 b = val; 91 b = base;
56 } else { 92 break;
57 base = ((255 - sat) * val) >> 8; 93 case 1:
58 94 r = val - color;
59 switch (hue / 60) { 95 g = val;
60 case 0: 96 b = base;
61 r = val; 97 break;
62 g = (((val - base)*hue) / 60) + base; 98 case 2:
63 b = base; 99 r = base;
64 break; 100 g = val;
65 101 b = base + color;
66 case 1: 102 break;
67 r = (((val - base)*(60 - (hue % 60))) / 60) + base; 103 case 3:
68 g = val; 104 r = base;
69 b = base; 105 g = val - color;
70 break; 106 b = val;
71 107 break;
72 case 2: 108 case 4:
73 r = base; 109 r = base + color;
74 g = val; 110 g = base;
75 b = (((val - base)*(hue % 60)) / 60) + base; 111 b = val;
76 break; 112 break;
77 113 case 5:
78 case 3: 114 r = val;
79 r = base; 115 g = base;
80 g = (((val - base)*(60 - (hue % 60))) / 60) + base; 116 b = val - color;
81 b = val; 117 break;
82 break; 118 }
83 119 }
84 case 4: 120 r = pgm_read_byte(&DIM_CURVE[r]);
85 r = (((val - base)*(hue % 60)) / 60) + base; 121 g = pgm_read_byte(&DIM_CURVE[g]);
86 g = base; 122 b = pgm_read_byte(&DIM_CURVE[b]);
87 b = val; 123
88 break; 124 setrgb(r, g, b, led1);
89
90 case 5:
91 r = val;
92 g = base;
93 b = (((val - base)*(60 - (hue % 60))) / 60) + base;
94 break;
95 }
96 }
97 setrgb(r,g,b, led1);
98} 125}
99 126
100void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { 127void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) {
@@ -107,46 +134,48 @@ void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) {
107uint32_t eeconfig_read_rgblight(void) { 134uint32_t eeconfig_read_rgblight(void) {
108 return eeprom_read_dword(EECONFIG_RGBLIGHT); 135 return eeprom_read_dword(EECONFIG_RGBLIGHT);
109} 136}
110void eeconfig_write_rgblight(uint32_t val) { 137void eeconfig_update_rgblight(uint32_t val) {
111 eeprom_write_dword(EECONFIG_RGBLIGHT, val); 138 eeprom_update_dword(EECONFIG_RGBLIGHT, val);
112} 139}
113void eeconfig_write_rgblight_default(void) { 140void eeconfig_update_rgblight_default(void) {
114 dprintf("eeconfig_write_rgblight_default\n"); 141 dprintf("eeconfig_update_rgblight_default\n");
115 rgblight_config.enable = 1; 142 rgblight_config.enable = 1;
116 rgblight_config.mode = 1; 143 rgblight_config.mode = 1;
117 rgblight_config.hue = 200; 144 rgblight_config.hue = 200;
118 rgblight_config.sat = 204; 145 rgblight_config.sat = 204;
119 rgblight_config.val = 204; 146 rgblight_config.val = 204;
120 eeconfig_write_rgblight(rgblight_config.raw); 147 eeconfig_update_rgblight(rgblight_config.raw);
121} 148}
122void eeconfig_debug_rgblight(void) { 149void eeconfig_debug_rgblight(void) {
123 dprintf("rgblight_config eprom\n"); 150 dprintf("rgblight_config eprom\n");
124 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); 151 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
125 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); 152 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
126 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); 153 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
127 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); 154 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
128 dprintf("rgblight_config.val = %d\n", rgblight_config.val); 155 dprintf("rgblight_config.val = %d\n", rgblight_config.val);
129} 156}
130 157
131void rgblight_init(void) { 158void rgblight_init(void) {
132 debug_enable = 1; // Debug ON! 159 debug_enable = 1; // Debug ON!
133 dprintf("rgblight_init called.\n"); 160 dprintf("rgblight_init called.\n");
134 rgblight_inited = 1; 161 rgblight_inited = 1;
135 dprintf("rgblight_init start!\n"); 162 dprintf("rgblight_init start!\n");
136 if (!eeconfig_is_enabled()) { 163 if (!eeconfig_is_enabled()) {
137 dprintf("rgblight_init eeconfig is not enabled.\n"); 164 dprintf("rgblight_init eeconfig is not enabled.\n");
138 eeconfig_init(); 165 eeconfig_init();
139 eeconfig_write_rgblight_default(); 166 eeconfig_update_rgblight_default();
140 } 167 }
141 rgblight_config.raw = eeconfig_read_rgblight(); 168 rgblight_config.raw = eeconfig_read_rgblight();
142 if (!rgblight_config.mode) { 169 if (!rgblight_config.mode) {
143 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); 170 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
144 eeconfig_write_rgblight_default(); 171 eeconfig_update_rgblight_default();
145 rgblight_config.raw = eeconfig_read_rgblight(); 172 rgblight_config.raw = eeconfig_read_rgblight();
146 } 173 }
147 eeconfig_debug_rgblight(); // display current eeprom values 174 eeconfig_debug_rgblight(); // display current eeprom values
148 175
149 rgblight_timer_init(); // setup the timer 176 #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
177 rgblight_timer_init(); // setup the timer
178 #endif
150 179
151 if (rgblight_config.enable) { 180 if (rgblight_config.enable) {
152 rgblight_mode(rgblight_config.mode); 181 rgblight_mode(rgblight_config.mode);
@@ -154,352 +183,376 @@ void rgblight_init(void) {
154} 183}
155 184
156void rgblight_increase(void) { 185void rgblight_increase(void) {
157 uint8_t mode; 186 uint8_t mode = 0;
158 if (rgblight_config.mode < RGBLIGHT_MODES) { 187 if (rgblight_config.mode < RGBLIGHT_MODES) {
159 mode = rgblight_config.mode + 1; 188 mode = rgblight_config.mode + 1;
160 } 189 }
161 rgblight_mode(mode); 190 rgblight_mode(mode);
162} 191}
163
164void rgblight_decrease(void) { 192void rgblight_decrease(void) {
165 uint8_t mode; 193 uint8_t mode = 0;
166 if (rgblight_config.mode > 1) { //mode will never < 1, if mode is less than 1, eeprom need to be initialized. 194 // Mode will never be < 1. If it ever is, eeprom needs to be initialized.
167 mode = rgblight_config.mode-1; 195 if (rgblight_config.mode > 1) {
196 mode = rgblight_config.mode - 1;
168 } 197 }
169 rgblight_mode(mode); 198 rgblight_mode(mode);
170} 199}
171
172void rgblight_step(void) { 200void rgblight_step(void) {
173 uint8_t mode; 201 uint8_t mode = 0;
174 mode = rgblight_config.mode + 1; 202 mode = rgblight_config.mode + 1;
175 if (mode > RGBLIGHT_MODES) { 203 if (mode > RGBLIGHT_MODES) {
176 mode = 1; 204 mode = 1;
177 } 205 }
178 rgblight_mode(mode); 206 rgblight_mode(mode);
179} 207}
180 208
181void rgblight_mode(uint8_t mode) { 209void rgblight_mode(uint8_t mode) {
182 if (!rgblight_config.enable) { 210 if (!rgblight_config.enable) {
183 return; 211 return;
184 } 212 }
185 if (mode<1) { 213 if (mode < 1) {
186 rgblight_config.mode = 1; 214 rgblight_config.mode = 1;
187 } else if (mode > RGBLIGHT_MODES) { 215 } else if (mode > RGBLIGHT_MODES) {
188 rgblight_config.mode = RGBLIGHT_MODES; 216 rgblight_config.mode = RGBLIGHT_MODES;
189 } else { 217 } else {
190 rgblight_config.mode = mode; 218 rgblight_config.mode = mode;
191 } 219 }
192 eeconfig_write_rgblight(rgblight_config.raw); 220 eeconfig_update_rgblight(rgblight_config.raw);
193 dprintf("rgblight mode: %u\n", rgblight_config.mode); 221 xprintf("rgblight mode: %u\n", rgblight_config.mode);
194 if (rgblight_config.mode == 1) { 222 if (rgblight_config.mode == 1) {
195 rgblight_timer_disable(); 223 #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
196 } else if (rgblight_config.mode >=2 && rgblight_config.mode <=23) { 224 rgblight_timer_disable();
197 // MODE 2-5, breathing 225 #endif
198 // MODE 6-8, rainbow mood 226 } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 23) {
199 // MODE 9-14, rainbow swirl 227 // MODE 2-5, breathing
200 // MODE 15-20, snake 228 // MODE 6-8, rainbow mood
201 // MODE 21-23, knight 229 // MODE 9-14, rainbow swirl
202 rgblight_timer_enable(); 230 // MODE 15-20, snake
203 } 231 // MODE 21-23, knight
232
233 #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
234 rgblight_timer_enable();
235 #endif
236 }
204 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); 237 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
205} 238}
206 239
207void rgblight_toggle(void) { 240void rgblight_toggle(void) {
208 rgblight_config.enable ^= 1; 241 rgblight_config.enable ^= 1;
209 eeconfig_write_rgblight(rgblight_config.raw); 242 eeconfig_update_rgblight(rgblight_config.raw);
210 dprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable); 243 xprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable);
211 if (rgblight_config.enable) { 244 if (rgblight_config.enable) {
212 rgblight_mode(rgblight_config.mode); 245 rgblight_mode(rgblight_config.mode);
213 } else { 246 } else {
214 rgblight_timer_disable(); 247 #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
215 _delay_ms(50); 248 rgblight_timer_disable();
216 rgblight_set(); 249 #endif
217 } 250 _delay_ms(50);
251 rgblight_set();
252 }
218} 253}
219 254
220 255
221void rgblight_increase_hue(void){ 256void rgblight_increase_hue(void) {
222 uint16_t hue; 257 uint16_t hue;
223 hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360; 258 hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360;
224 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); 259 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
225} 260}
226void rgblight_decrease_hue(void){ 261void rgblight_decrease_hue(void) {
227 uint16_t hue; 262 uint16_t hue;
228 if (rgblight_config.hue-RGBLIGHT_HUE_STEP <0 ) { 263 if (rgblight_config.hue-RGBLIGHT_HUE_STEP < 0) {
229 hue = (rgblight_config.hue+360-RGBLIGHT_HUE_STEP) % 360; 264 hue = (rgblight_config.hue + 360 - RGBLIGHT_HUE_STEP) % 360;
230 } else { 265 } else {
231 hue = (rgblight_config.hue-RGBLIGHT_HUE_STEP) % 360; 266 hue = (rgblight_config.hue - RGBLIGHT_HUE_STEP) % 360;
232 } 267 }
233 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); 268 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
234} 269}
235void rgblight_increase_sat(void) { 270void rgblight_increase_sat(void) {
236 uint8_t sat; 271 uint8_t sat;
237 if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) { 272 if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) {
238 sat = 255; 273 sat = 255;
239 } else { 274 } else {
240 sat = rgblight_config.sat+RGBLIGHT_SAT_STEP; 275 sat = rgblight_config.sat + RGBLIGHT_SAT_STEP;
241 } 276 }
242 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); 277 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
243} 278}
244void rgblight_decrease_sat(void){ 279void rgblight_decrease_sat(void) {
245 uint8_t sat; 280 uint8_t sat;
246 if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) { 281 if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) {
247 sat = 0; 282 sat = 0;
248 } else { 283 } else {
249 sat = rgblight_config.sat-RGBLIGHT_SAT_STEP; 284 sat = rgblight_config.sat - RGBLIGHT_SAT_STEP;
250 } 285 }
251 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); 286 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
252} 287}
253void rgblight_increase_val(void){ 288void rgblight_increase_val(void) {
254 uint8_t val; 289 uint8_t val;
255 if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) { 290 if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) {
256 val = 255; 291 val = 255;
257 } else { 292 } else {
258 val = rgblight_config.val+RGBLIGHT_VAL_STEP; 293 val = rgblight_config.val + RGBLIGHT_VAL_STEP;
259 } 294 }
260 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); 295 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
261} 296}
262void rgblight_decrease_val(void) { 297void rgblight_decrease_val(void) {
263 uint8_t val; 298 uint8_t val;
264 if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) { 299 if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) {
265 val = 0; 300 val = 0;
266 } else { 301 } else {
267 val = rgblight_config.val-RGBLIGHT_VAL_STEP; 302 val = rgblight_config.val - RGBLIGHT_VAL_STEP;
268 } 303 }
269 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); 304 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
270} 305}
271 306
272void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val){ 307void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
273 inmem_config.raw = rgblight_config.raw; 308 inmem_config.raw = rgblight_config.raw;
274 if (rgblight_config.enable) { 309 if (rgblight_config.enable) {
275 struct cRGB tmp_led; 310 struct cRGB tmp_led;
276 sethsv(hue, sat, val, &tmp_led); 311 sethsv(hue, sat, val, &tmp_led);
277 inmem_config.hue = hue; 312 inmem_config.hue = hue;
278 inmem_config.sat = sat; 313 inmem_config.sat = sat;
279 inmem_config.val = val; 314 inmem_config.val = val;
280 // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val); 315 // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val);
281 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); 316 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
282 } 317 }
283} 318}
284void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val){ 319void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
285 if (rgblight_config.enable) { 320 if (rgblight_config.enable) {
286 if (rgblight_config.mode == 1) { 321 if (rgblight_config.mode == 1) {
287 // same static color 322 // same static color
288 rgblight_sethsv_noeeprom(hue, sat, val); 323 rgblight_sethsv_noeeprom(hue, sat, val);
289 } else { 324 } else {
290 // all LEDs in same color 325 // all LEDs in same color
291 if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { 326 if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
292 // breathing mode, ignore the change of val, use in memory value instead 327 // breathing mode, ignore the change of val, use in memory value instead
293 val = rgblight_config.val; 328 val = rgblight_config.val;
294 } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) { 329 } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) {
295 // rainbow mood and rainbow swirl, ignore the change of hue 330 // rainbow mood and rainbow swirl, ignore the change of hue
296 hue = rgblight_config.hue; 331 hue = rgblight_config.hue;
297 } 332 }
298 } 333 }
299 rgblight_config.hue = hue; 334 rgblight_config.hue = hue;
300 rgblight_config.sat = sat; 335 rgblight_config.sat = sat;
301 rgblight_config.val = val; 336 rgblight_config.val = val;
302 eeconfig_write_rgblight(rgblight_config.raw); 337 eeconfig_update_rgblight(rgblight_config.raw);
303 dprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); 338 xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
304 } 339 }
305} 340}
306 341
307void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b){ 342void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
308 // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b); 343 // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b);
309 for (uint8_t i=0;i<RGBLED_NUM;i++) { 344 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
310 led[i].r = r; 345 led[i].r = r;
311 led[i].g = g; 346 led[i].g = g;
312 led[i].b = b; 347 led[i].b = b;
313 } 348 }
314 rgblight_set(); 349 rgblight_set();
315
316} 350}
317 351
318void rgblight_set(void) { 352void rgblight_set(void) {
319 if (rgblight_config.enable) { 353 if (rgblight_config.enable) {
320 ws2812_setleds(led, RGBLED_NUM); 354 ws2812_setleds(led, RGBLED_NUM);
321 } else { 355 } else {
322 for (uint8_t i=0;i<RGBLED_NUM;i++) { 356 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
323 led[i].r = 0; 357 led[i].r = 0;
324 led[i].g = 0; 358 led[i].g = 0;
325 led[i].b = 0; 359 led[i].b = 0;
326 } 360 }
327 ws2812_setleds(led, RGBLED_NUM); 361 ws2812_setleds(led, RGBLED_NUM);
328 } 362 }
329} 363}
330 364
365#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
366
331// Animation timer -- AVR Timer3 367// Animation timer -- AVR Timer3
332void rgblight_timer_init(void) { 368void rgblight_timer_init(void) {
333 static uint8_t rgblight_timer_is_init = 0; 369 static uint8_t rgblight_timer_is_init = 0;
334 if (rgblight_timer_is_init) { 370 if (rgblight_timer_is_init) {
335 return; 371 return;
336 } 372 }
337 rgblight_timer_is_init = 1; 373 rgblight_timer_is_init = 1;
338 /* Timer 3 setup */ 374 /* Timer 3 setup */
339 TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP 375 TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP
340 | _BV(CS30); //Clock selelct: clk/1 376 | _BV(CS30); //Clock selelct: clk/1
341 /* Set TOP value */ 377 /* Set TOP value */
342 uint8_t sreg = SREG; 378 uint8_t sreg = SREG;
343 cli(); 379 cli();
344 OCR3AH = (RGBLED_TIMER_TOP>>8)&0xff; 380 OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
345 OCR3AL = RGBLED_TIMER_TOP&0xff; 381 OCR3AL = RGBLED_TIMER_TOP & 0xff;
346 SREG = sreg; 382 SREG = sreg;
347} 383}
348void rgblight_timer_enable(void) { 384void rgblight_timer_enable(void) {
349 TIMSK3 |= _BV(OCIE3A); 385 TIMSK3 |= _BV(OCIE3A);
350 dprintf("TIMER3 enabled.\n"); 386 dprintf("TIMER3 enabled.\n");
351} 387}
352void rgblight_timer_disable(void) { 388void rgblight_timer_disable(void) {
353 TIMSK3 &= ~_BV(OCIE3A); 389 TIMSK3 &= ~_BV(OCIE3A);
354 dprintf("TIMER3 disabled.\n"); 390 dprintf("TIMER3 disabled.\n");
355} 391}
356void rgblight_timer_toggle(void) { 392void rgblight_timer_toggle(void) {
357 TIMSK3 ^= _BV(OCIE3A); 393 TIMSK3 ^= _BV(OCIE3A);
358 dprintf("TIMER3 toggled.\n"); 394 dprintf("TIMER3 toggled.\n");
359} 395}
360 396
361ISR(TIMER3_COMPA_vect) { 397ISR(TIMER3_COMPA_vect) {
362 // Mode = 1, static light, do nothing here 398 // mode = 1, static light, do nothing here
363 if (rgblight_config.mode>=2 && rgblight_config.mode<=5) { 399 if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
364 // mode = 2 to 5, breathing mode 400 // mode = 2 to 5, breathing mode
365 rgblight_effect_breathing(rgblight_config.mode-2); 401 rgblight_effect_breathing(rgblight_config.mode - 2);
366 402 } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) {
367 } else if (rgblight_config.mode>=6 && rgblight_config.mode<=8) { 403 // mode = 6 to 8, rainbow mood mod
368 rgblight_effect_rainbow_mood(rgblight_config.mode-6); 404 rgblight_effect_rainbow_mood(rgblight_config.mode - 6);
369 } else if (rgblight_config.mode>=9 && rgblight_config.mode<=14) { 405 } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) {
370 rgblight_effect_rainbow_swirl(rgblight_config.mode-9); 406 // mode = 9 to 14, rainbow swirl mode
371 } else if (rgblight_config.mode>=15 && rgblight_config.mode<=20) { 407 rgblight_effect_rainbow_swirl(rgblight_config.mode - 9);
372 rgblight_effect_snake(rgblight_config.mode-15); 408 } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) {
373 } else if (rgblight_config.mode>=21 && rgblight_config.mode<=23) { 409 // mode = 15 to 20, snake mode
374 rgblight_effect_knight(rgblight_config.mode-21); 410 rgblight_effect_snake(rgblight_config.mode - 15);
375 } 411 } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) {
376} 412 // mode = 21 to 23, knight mode
377 413 rgblight_effect_knight(rgblight_config.mode - 21);
378// effects 414 }
415}
416
417// Effects
379void rgblight_effect_breathing(uint8_t interval) { 418void rgblight_effect_breathing(uint8_t interval) {
380 static uint8_t pos = 0; 419 static uint8_t pos = 0;
381 static uint16_t last_timer = 0; 420 static uint16_t last_timer = 0;
382 421
383 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) return; 422 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) {
384 last_timer = timer_read(); 423 return;
424 }
425 last_timer = timer_read();
385 426
386 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos])); 427 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos]));
387 pos = (pos+1) % 256; 428 pos = (pos + 1) % 256;
388} 429}
389
390void rgblight_effect_rainbow_mood(uint8_t interval) { 430void rgblight_effect_rainbow_mood(uint8_t interval) {
391 static uint16_t current_hue=0; 431 static uint16_t current_hue = 0;
392 static uint16_t last_timer = 0; 432 static uint16_t last_timer = 0;
393 433
394 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) return; 434 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) {
395 last_timer = timer_read(); 435 return;
396 rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val); 436 }
397 current_hue = (current_hue+1) % 360; 437 last_timer = timer_read();
438 rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val);
439 current_hue = (current_hue + 1) % 360;
398} 440}
399
400void rgblight_effect_rainbow_swirl(uint8_t interval) { 441void rgblight_effect_rainbow_swirl(uint8_t interval) {
401 static uint16_t current_hue=0; 442 static uint16_t current_hue = 0;
402 static uint16_t last_timer = 0; 443 static uint16_t last_timer = 0;
403 uint16_t hue; 444 uint16_t hue;
404 uint8_t i; 445 uint8_t i;
405 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval/2])) return; 446 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval / 2])) {
406 last_timer = timer_read(); 447 return;
407 for (i=0; i<RGBLED_NUM; i++) { 448 }
408 hue = (360/RGBLED_NUM*i+current_hue)%360; 449 last_timer = timer_read();
409 sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]); 450 for (i = 0; i < RGBLED_NUM; i++) {
410 } 451 hue = (360 / RGBLED_NUM * i + current_hue) % 360;
411 rgblight_set(); 452 sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]);
412 453 }
413 if (interval % 2) { 454 rgblight_set();
414 current_hue = (current_hue+1) % 360; 455
415 } else { 456 if (interval % 2) {
416 if (current_hue -1 < 0) { 457 current_hue = (current_hue + 1) % 360;
417 current_hue = 359; 458 } else {
418 } else { 459 if (current_hue - 1 < 0) {
419 current_hue = current_hue - 1; 460 current_hue = 359;
420 } 461 } else {
421 462 current_hue = current_hue - 1;
422 } 463 }
464 }
423} 465}
424void rgblight_effect_snake(uint8_t interval) { 466void rgblight_effect_snake(uint8_t interval) {
425 static uint8_t pos=0; 467 static uint8_t pos = 0;
426 static uint16_t last_timer = 0; 468 static uint16_t last_timer = 0;
427 uint8_t i,j; 469 uint8_t i, j;
428 int8_t k; 470 int8_t k;
429 int8_t increament = 1; 471 int8_t increment = 1;
430 if (interval%2) increament = -1; 472 if (interval % 2) {
431 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval/2])) return; 473 increment = -1;
432 last_timer = timer_read(); 474 }
433 for (i=0;i<RGBLED_NUM;i++) { 475 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval / 2])) {
434 led[i].r=0; 476 return;
435 led[i].g=0; 477 }
436 led[i].b=0; 478 last_timer = timer_read();
437 for (j=0;j<RGBLIGHT_EFFECT_SNAKE_LENGTH;j++) { 479 for (i = 0; i < RGBLED_NUM; i++) {
438 k = pos+j*increament; 480 led[i].r = 0;
439 if (k<0) k = k+RGBLED_NUM; 481 led[i].g = 0;
440 if (i==k) { 482 led[i].b = 0;
441 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]); 483 for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
442 } 484 k = pos + j * increment;
443 } 485 if (k < 0) {
444 } 486 k = k + RGBLED_NUM;
445 rgblight_set(); 487 }
446 if (increament == 1) { 488 if (i == k) {
447 if (pos - 1 < 0) { 489 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]);
448 pos = RGBLED_NUM-1; 490 }
449 } else { 491 }
450 pos -= 1; 492 }
451 } 493 rgblight_set();
452 } else { 494 if (increment == 1) {
453 pos = (pos+1)%RGBLED_NUM; 495 if (pos - 1 < 0) {
454 } 496 pos = RGBLED_NUM - 1;
455 497 } else {
498 pos -= 1;
499 }
500 } else {
501 pos = (pos + 1) % RGBLED_NUM;
502 }
456} 503}
457
458void rgblight_effect_knight(uint8_t interval) { 504void rgblight_effect_knight(uint8_t interval) {
459 static int8_t pos=0; 505 static int8_t pos = 0;
460 static uint16_t last_timer = 0; 506 static uint16_t last_timer = 0;
461 uint8_t i,j,cur; 507 uint8_t i, j, cur;
462 int8_t k; 508 int8_t k;
463 struct cRGB preled[RGBLED_NUM]; 509 struct cRGB preled[RGBLED_NUM];
464 static int8_t increament = -1; 510 static int8_t increment = -1;
465 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) return; 511 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) {
466 last_timer = timer_read(); 512 return;
467 for (i=0;i<RGBLED_NUM;i++) { 513 }
468 preled[i].r=0; 514 last_timer = timer_read();
469 preled[i].g=0; 515 for (i = 0; i < RGBLED_NUM; i++) {
470 preled[i].b=0; 516 preled[i].r = 0;
471 for (j=0;j<RGBLIGHT_EFFECT_KNIGHT_LENGTH;j++) { 517 preled[i].g = 0;
472 k = pos+j*increament; 518 preled[i].b = 0;
473 if (k<0) k = 0; 519 for (j = 0; j < RGBLIGHT_EFFECT_KNIGHT_LENGTH; j++) {
474 if (k>=RGBLED_NUM) k=RGBLED_NUM-1; 520 k = pos + j * increment;
475 if (i==k) { 521 if (k < 0) {
476 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); 522 k = 0;
477 } 523 }
478 } 524 if (k >= RGBLED_NUM) {
479 } 525 k = RGBLED_NUM - 1;
480 if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) { 526 }
481 for (i=0;i<RGBLED_NUM;i++) { 527 if (i == k) {
482 cur = (i+RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM; 528 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]);
483 led[i].r = preled[cur].r; 529 }
484 led[i].g = preled[cur].g; 530 }
485 led[i].b = preled[cur].b; 531 }
486 } 532 if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) {
487 } 533 for (i = 0; i < RGBLED_NUM; i++) {
488 rgblight_set(); 534 cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM;
489 if (increament == 1) { 535 led[i].r = preled[cur].r;
490 if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) { 536 led[i].g = preled[cur].g;
491 pos = 0- RGBLIGHT_EFFECT_KNIGHT_LENGTH; 537 led[i].b = preled[cur].b;
492 increament = -1; 538 }
493 } else { 539 }
494 pos -= 1; 540 rgblight_set();
495 } 541 if (increment == 1) {
496 } else { 542 if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) {
497 if (pos+1>RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH) { 543 pos = 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH;
498 pos = RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH-1; 544 increment = -1;
499 increament = 1; 545 } else {
500 } else { 546 pos -= 1;
501 pos += 1; 547 }
502 } 548 } else {
503 } 549 if (pos + 1 > RGBLED_NUM + RGBLIGHT_EFFECT_KNIGHT_LENGTH) {
504 550 pos = RGBLED_NUM + RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
551 increment = 1;
552 } else {
553 pos += 1;
554 }
555 }
505} 556}
557
558#endif
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
index 9e1562328..17f04ffcf 100644
--- a/quantum/rgblight.h
+++ b/quantum/rgblight.h
@@ -1,8 +1,11 @@
1#ifndef RGBLIGHT_H 1#ifndef RGBLIGHT_H
2#define RGBLIGHT_H 2#define RGBLIGHT_H
3 3
4#ifndef RGBLIGHT_MODES 4
5#define RGBLIGHT_MODES 23 5#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER)
6 #define RGBLIGHT_MODES 23
7#else
8 #define RGBLIGHT_MODES 1
6#endif 9#endif
7 10
8#ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH 11#ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH
@@ -37,6 +40,12 @@
37#include "eeconfig.h" 40#include "eeconfig.h"
38#include "light_ws2812.h" 41#include "light_ws2812.h"
39 42
43extern const uint8_t RGBLED_BREATHING_INTERVALS[4] PROGMEM;
44extern const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[3] PROGMEM;
45extern const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[3] PROGMEM;
46extern const uint8_t RGBLED_SNAKE_INTERVALS[3] PROGMEM;
47extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM;
48
40typedef union { 49typedef union {
41 uint32_t raw; 50 uint32_t raw;
42 struct { 51 struct {
@@ -64,10 +73,9 @@ void rgblight_decrease_val(void);
64void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val); 73void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val);
65void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b); 74void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b);
66 75
67#define EECONFIG_RGBLIGHT (uint8_t *)7
68uint32_t eeconfig_read_rgblight(void); 76uint32_t eeconfig_read_rgblight(void);
69void eeconfig_write_rgblight(uint32_t val); 77void eeconfig_update_rgblight(uint32_t val);
70void eeconfig_write_rgblight_default(void); 78void eeconfig_update_rgblight_default(void);
71void eeconfig_debug_rgblight(void); 79void eeconfig_debug_rgblight(void);
72 80
73void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); 81void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1);
diff --git a/quantum/serial_link/LICENSE b/quantum/serial_link/LICENSE
new file mode 100644
index 000000000..d7cc3198c
--- /dev/null
+++ b/quantum/serial_link/LICENSE
@@ -0,0 +1,21 @@
1The MIT License (MIT)
2
3Copyright (c) 2016 Fred Sundvik
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/quantum/serial_link/README.md b/quantum/serial_link/README.md
new file mode 100644
index 000000000..e8490e290
--- /dev/null
+++ b/quantum/serial_link/README.md
@@ -0,0 +1 @@
# qmk_serial_link \ No newline at end of file
diff --git a/quantum/serial_link/protocol/byte_stuffer.c b/quantum/serial_link/protocol/byte_stuffer.c
new file mode 100644
index 000000000..2c87d64c2
--- /dev/null
+++ b/quantum/serial_link/protocol/byte_stuffer.c
@@ -0,0 +1,142 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/byte_stuffer.h"
26#include "serial_link/protocol/frame_validator.h"
27#include "serial_link/protocol/physical.h"
28#include <stdbool.h>
29
30// This implements the "Consistent overhead byte stuffing protocol"
31// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
32// http://www.stuartcheshire.org/papers/COBSforToN.pdf
33
34typedef struct byte_stuffer_state {
35 uint16_t next_zero;
36 uint16_t data_pos;
37 bool long_frame;
38 uint8_t data[MAX_FRAME_SIZE];
39}byte_stuffer_state_t;
40
41static byte_stuffer_state_t states[NUM_LINKS];
42
43void init_byte_stuffer_state(byte_stuffer_state_t* state) {
44 state->next_zero = 0;
45 state->data_pos = 0;
46 state->long_frame = false;
47}
48
49void init_byte_stuffer(void) {
50 int i;
51 for (i=0;i<NUM_LINKS;i++) {
52 init_byte_stuffer_state(&states[i]);
53 }
54}
55
56void byte_stuffer_recv_byte(uint8_t link, uint8_t data) {
57 byte_stuffer_state_t* state = &states[link];
58 // Start of a new frame
59 if (state->next_zero == 0) {
60 state->next_zero = data;
61 state->long_frame = data == 0xFF;
62 state->data_pos = 0;
63 return;
64 }
65
66 state->next_zero--;
67 if (data == 0) {
68 if (state->next_zero == 0) {
69 // The frame is completed
70 if (state->data_pos > 0) {
71 validator_recv_frame(link, state->data, state->data_pos);
72 }
73 }
74 else {
75 // The frame is invalid, so reset
76 init_byte_stuffer_state(state);
77 }
78 }
79 else {
80 if (state->data_pos == MAX_FRAME_SIZE) {
81 // We exceeded our maximum frame size
82 // therefore there's nothing else to do than reset to a new frame
83 state->next_zero = data;
84 state->long_frame = data == 0xFF;
85 state->data_pos = 0;
86 }
87 else if (state->next_zero == 0) {
88 if (state->long_frame) {
89 // This is part of a long frame, so continue
90 state->next_zero = data;
91 state->long_frame = data == 0xFF;
92 }
93 else {
94 // Special case for zeroes
95 state->next_zero = data;
96 state->data[state->data_pos++] = 0;
97 }
98 }
99 else {
100 state->data[state->data_pos++] = data;
101 }
102 }
103}
104
105static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) {
106 send_data(link, &num_non_zero, 1);
107 if (end > start) {
108 send_data(link, start, end-start);
109 }
110}
111
112void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
113 const uint8_t zero = 0;
114 if (size > 0) {
115 uint16_t num_non_zero = 1;
116 uint8_t* end = data + size;
117 uint8_t* start = data;
118 while (data < end) {
119 if (num_non_zero == 0xFF) {
120 // There's more data after big non-zero block
121 // So send it, and start a new block
122 send_block(link, start, data, num_non_zero);
123 start = data;
124 num_non_zero = 1;
125 }
126 else {
127 if (*data == 0) {
128 // A zero encountered, so send the block
129 send_block(link, start, data, num_non_zero);
130 start = data + 1;
131 num_non_zero = 1;
132 }
133 else {
134 num_non_zero++;
135 }
136 ++data;
137 }
138 }
139 send_block(link, start, data, num_non_zero);
140 send_data(link, &zero, 1);
141 }
142}
diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h
new file mode 100644
index 000000000..97e896856
--- /dev/null
+++ b/quantum/serial_link/protocol/byte_stuffer.h
@@ -0,0 +1,37 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_BYTE_STUFFER_H
26#define SERIAL_LINK_BYTE_STUFFER_H
27
28#include <stdint.h>
29
30#define MAX_FRAME_SIZE 1024
31#define NUM_LINKS 2
32
33void init_byte_stuffer(void);
34void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
35void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);
36
37#endif
diff --git a/quantum/serial_link/protocol/frame_router.c b/quantum/serial_link/protocol/frame_router.c
new file mode 100644
index 000000000..04b8c2e75
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_router.c
@@ -0,0 +1,69 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/frame_router.h"
26#include "serial_link/protocol/transport.h"
27#include "serial_link/protocol/frame_validator.h"
28
29static bool is_master;
30
31void router_set_master(bool master) {
32 is_master = master;
33}
34
35void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size){
36 if (is_master) {
37 if (link == DOWN_LINK) {
38 transport_recv_frame(data[size-1], data, size - 1);
39 }
40 }
41 else {
42 if (link == UP_LINK) {
43 if (data[size-1] & 1) {
44 transport_recv_frame(0, data, size - 1);
45 }
46 data[size-1] >>= 1;
47 validator_send_frame(DOWN_LINK, data, size);
48 }
49 else {
50 data[size-1]++;
51 validator_send_frame(UP_LINK, data, size);
52 }
53 }
54}
55
56void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
57 if (destination == 0) {
58 if (!is_master) {
59 data[size] = 1;
60 validator_send_frame(UP_LINK, data, size + 1);
61 }
62 }
63 else {
64 if (is_master) {
65 data[size] = destination;
66 validator_send_frame(DOWN_LINK, data, size + 1);
67 }
68 }
69}
diff --git a/quantum/serial_link/protocol/frame_router.h b/quantum/serial_link/protocol/frame_router.h
new file mode 100644
index 000000000..712250ff3
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_router.h
@@ -0,0 +1,38 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_FRAME_ROUTER_H
26#define SERIAL_LINK_FRAME_ROUTER_H
27
28#include <stdint.h>
29#include <stdbool.h>
30
31#define UP_LINK 0
32#define DOWN_LINK 1
33
34void router_set_master(bool master);
35void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size);
36void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size);
37
38#endif
diff --git a/quantum/serial_link/protocol/frame_validator.c b/quantum/serial_link/protocol/frame_validator.c
new file mode 100644
index 000000000..474f80ee8
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_validator.c
@@ -0,0 +1,121 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/frame_validator.h"
26#include "serial_link/protocol/frame_router.h"
27#include "serial_link/protocol/byte_stuffer.h"
28#include <string.h>
29
30const uint32_t poly8_lookup[256] =
31{
32 0, 0x77073096, 0xEE0E612C, 0x990951BA,
33 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
34 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
35 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
36 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
37 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
38 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
39 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
40 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
41 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
42 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
43 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
44 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
45 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
46 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
47 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
48 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
49 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
50 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
51 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
52 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
53 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
54 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
55 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
56 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
57 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
58 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
59 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
60 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
61 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
62 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
63 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
64 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
65 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
66 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
67 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
68 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
69 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
70 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
71 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
72 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
73 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
74 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
75 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
76 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
77 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
78 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
79 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
80 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
81 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
82 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
83 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
84 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
85 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
86 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
87 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
88 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
89 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
90 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
91 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
92 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
93 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
94 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
95 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
96};
97
98static uint32_t crc32_byte(uint8_t *p, uint32_t bytelength)
99{
100 uint32_t crc = 0xffffffff;
101 while (bytelength-- !=0) crc = poly8_lookup[((uint8_t) crc ^ *(p++))] ^ (crc >> 8);
102 // return (~crc); also works
103 return (crc ^ 0xffffffff);
104}
105
106void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
107 if (size > 4) {
108 uint32_t frame_crc;
109 memcpy(&frame_crc, data + size -4, 4);
110 uint32_t expected_crc = crc32_byte(data, size - 4);
111 if (frame_crc == expected_crc) {
112 route_incoming_frame(link, data, size-4);
113 }
114 }
115}
116
117void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
118 uint32_t crc = crc32_byte(data, size);
119 memcpy(data + size, &crc, 4);
120 byte_stuffer_send_frame(link, data, size + 4);
121}
diff --git a/quantum/serial_link/protocol/frame_validator.h b/quantum/serial_link/protocol/frame_validator.h
new file mode 100644
index 000000000..4a910d510
--- /dev/null
+++ b/quantum/serial_link/protocol/frame_validator.h
@@ -0,0 +1,34 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_FRAME_VALIDATOR_H
26#define SERIAL_LINK_FRAME_VALIDATOR_H
27
28#include <stdint.h>
29
30void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size);
31// The buffer pointed to by the data needs 4 additional bytes
32void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size);
33
34#endif
diff --git a/quantum/serial_link/protocol/physical.h b/quantum/serial_link/protocol/physical.h
new file mode 100644
index 000000000..425e06cdd
--- /dev/null
+++ b/quantum/serial_link/protocol/physical.h
@@ -0,0 +1,30 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_PHYSICAL_H
26#define SERIAL_LINK_PHYSICAL_H
27
28void send_data(uint8_t link, const uint8_t* data, uint16_t size);
29
30#endif
diff --git a/quantum/serial_link/protocol/transport.c b/quantum/serial_link/protocol/transport.c
new file mode 100644
index 000000000..ff795fe20
--- /dev/null
+++ b/quantum/serial_link/protocol/transport.c
@@ -0,0 +1,128 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/transport.h"
26#include "serial_link/protocol/frame_router.h"
27#include "serial_link/protocol/triple_buffered_object.h"
28#include <string.h>
29
30#define MAX_REMOTE_OBJECTS 16
31static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS];
32static uint32_t num_remote_objects = 0;
33
34void reinitialize_serial_link_transport(void) {
35 num_remote_objects = 0;
36}
37
38void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
39 unsigned int i;
40 for(i=0;i<_num_remote_objects;i++) {
41 remote_object_t* obj = _remote_objects[i];
42 remote_objects[num_remote_objects++] = obj;
43 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
44 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
45 triple_buffer_init(tb);
46 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
47 tb = (triple_buffer_object_t*)start;
48 triple_buffer_init(tb);
49 }
50 else if(obj->object_type == MASTER_TO_SINGLE_SLAVE) {
51 uint8_t* start = obj->buffer;
52 unsigned int j;
53 for (j=0;j<NUM_SLAVES;j++) {
54 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
55 triple_buffer_init(tb);
56 start += LOCAL_OBJECT_SIZE(obj->object_size);
57 }
58 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
59 triple_buffer_init(tb);
60 }
61 else {
62 uint8_t* start = obj->buffer;
63 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
64 triple_buffer_init(tb);
65 start += LOCAL_OBJECT_SIZE(obj->object_size);
66 unsigned int j;
67 for (j=0;j<NUM_SLAVES;j++) {
68 tb = (triple_buffer_object_t*)start;
69 triple_buffer_init(tb);
70 start += REMOTE_OBJECT_SIZE(obj->object_size);
71 }
72 }
73 }
74}
75
76void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
77 uint8_t id = data[size-1];
78 if (id < num_remote_objects) {
79 remote_object_t* obj = remote_objects[id];
80 if (obj->object_size == size - 1) {
81 uint8_t* start;
82 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
83 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
84 }
85 else if(obj->object_type == SLAVE_TO_MASTER) {
86 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
87 start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size);
88 }
89 else {
90 start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);
91 }
92 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
93 void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb);
94 memcpy(ptr, data, size - 1);
95 triple_buffer_end_write_internal(tb);
96 }
97 }
98}
99
100void update_transport(void) {
101 unsigned int i;
102 for(i=0;i<num_remote_objects;i++) {
103 remote_object_t* obj = remote_objects[i];
104 if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) {
105 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
106 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
107 if (ptr) {
108 ptr[obj->object_size] = i;
109 uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0;
110 router_send_frame(dest, ptr, obj->object_size + 1);
111 }
112 }
113 else {
114 uint8_t* start = obj->buffer;
115 unsigned int j;
116 for (j=0;j<NUM_SLAVES;j++) {
117 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
118 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
119 if (ptr) {
120 ptr[obj->object_size] = i;
121 uint8_t dest = j + 1;
122 router_send_frame(dest, ptr, obj->object_size + 1);
123 }
124 start += LOCAL_OBJECT_SIZE(obj->object_size);
125 }
126 }
127 }
128}
diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h
new file mode 100644
index 000000000..2c5d890b2
--- /dev/null
+++ b/quantum/serial_link/protocol/transport.h
@@ -0,0 +1,152 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_TRANSPORT_H
26#define SERIAL_LINK_TRANSPORT_H
27
28#include "serial_link/protocol/triple_buffered_object.h"
29#include "serial_link/system/serial_link.h"
30
31#define NUM_SLAVES 8
32#define LOCAL_OBJECT_EXTRA 16
33
34// master -> slave = 1 local(target all), 1 remote object
35// slave -> master = 1 local(target 0), multiple remote objects
36// master -> single slave (multiple local, target id), 1 remote object
37typedef enum {
38 MASTER_TO_ALL_SLAVES,
39 MASTER_TO_SINGLE_SLAVE,
40 SLAVE_TO_MASTER,
41} remote_object_type;
42
43typedef struct {
44 remote_object_type object_type;
45 uint16_t object_size;
46 uint8_t buffer[] __attribute__((aligned(4)));
47} remote_object_t;
48
49#define REMOTE_OBJECT_SIZE(objectsize) \
50 (sizeof(triple_buffer_object_t) + objectsize * 3)
51#define LOCAL_OBJECT_SIZE(objectsize) \
52 (sizeof(triple_buffer_object_t) + (objectsize + LOCAL_OBJECT_EXTRA) * 3)
53
54#define REMOTE_OBJECT_HELPER(name, type, num_local, num_remote) \
55typedef struct { \
56 remote_object_t object; \
57 uint8_t buffer[ \
58 num_remote * REMOTE_OBJECT_SIZE(sizeof(type)) + \
59 num_local * LOCAL_OBJECT_SIZE(sizeof(type))]; \
60} remote_object_##name##_t;
61
62#define MASTER_TO_ALL_SLAVES_OBJECT(name, type) \
63 REMOTE_OBJECT_HELPER(name, type, 1, 1) \
64 remote_object_##name##_t remote_object_##name = { \
65 .object = { \
66 .object_type = MASTER_TO_ALL_SLAVES, \
67 .object_size = sizeof(type), \
68 } \
69 }; \
70 type* begin_write_##name(void) { \
71 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
72 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
73 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
74 }\
75 void end_write_##name(void) { \
76 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
77 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
78 triple_buffer_end_write_internal(tb); \
79 signal_data_written(); \
80 }\
81 type* read_##name(void) { \
82 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
83 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
84 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
85 return (type*)triple_buffer_read_internal(obj->object_size, tb); \
86 }
87
88#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \
89 REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \
90 remote_object_##name##_t remote_object_##name = { \
91 .object = { \
92 .object_type = MASTER_TO_SINGLE_SLAVE, \
93 .object_size = sizeof(type), \
94 } \
95 }; \
96 type* begin_write_##name(uint8_t slave) { \
97 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
98 uint8_t* start = obj->buffer;\
99 start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \
100 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
101 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
102 }\
103 void end_write_##name(uint8_t slave) { \
104 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
105 uint8_t* start = obj->buffer;\
106 start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \
107 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
108 triple_buffer_end_write_internal(tb); \
109 signal_data_written(); \
110 }\
111 type* read_##name() { \
112 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
113 uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\
114 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
115 return (type*)triple_buffer_read_internal(obj->object_size, tb); \
116 }
117
118#define SLAVE_TO_MASTER_OBJECT(name, type) \
119 REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \
120 remote_object_##name##_t remote_object_##name = { \
121 .object = { \
122 .object_type = SLAVE_TO_MASTER, \
123 .object_size = sizeof(type), \
124 } \
125 }; \
126 type* begin_write_##name(void) { \
127 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
128 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
129 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
130 }\
131 void end_write_##name(void) { \
132 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
133 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
134 triple_buffer_end_write_internal(tb); \
135 signal_data_written(); \
136 }\
137 type* read_##name(uint8_t slave) { \
138 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
139 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
140 start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \
141 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
142 return (type*)triple_buffer_read_internal(obj->object_size, tb); \
143 }
144
145#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name
146
147void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects);
148void reinitialize_serial_link_transport(void);
149void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
150void update_transport(void);
151
152#endif
diff --git a/quantum/serial_link/protocol/triple_buffered_object.c b/quantum/serial_link/protocol/triple_buffered_object.c
new file mode 100644
index 000000000..e3e8989d3
--- /dev/null
+++ b/quantum/serial_link/protocol/triple_buffered_object.c
@@ -0,0 +1,78 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/triple_buffered_object.h"
26#include "serial_link/system/serial_link.h"
27#include <stdbool.h>
28#include <stddef.h>
29
30#define GET_READ_INDEX() object->state & 3
31#define GET_WRITE_INDEX() (object->state >> 2) & 3
32#define GET_SHARED_INDEX() (object->state >> 4) & 3
33#define GET_DATA_AVAILABLE() (object->state >> 6) & 1
34
35#define SET_READ_INDEX(i) object->state = ((object->state & ~3) | i)
36#define SET_WRITE_INDEX(i) object->state = ((object->state & ~(3 << 2)) | (i << 2))
37#define SET_SHARED_INDEX(i) object->state = ((object->state & ~(3 << 4)) | (i << 4))
38#define SET_DATA_AVAILABLE(i) object->state = ((object->state & ~(1 << 6)) | (i << 6))
39
40void triple_buffer_init(triple_buffer_object_t* object) {
41 object->state = 0;
42 SET_WRITE_INDEX(0);
43 SET_READ_INDEX(1);
44 SET_SHARED_INDEX(2);
45 SET_DATA_AVAILABLE(0);
46}
47
48void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object) {
49 serial_link_lock();
50 if (GET_DATA_AVAILABLE()) {
51 uint8_t shared_index = GET_SHARED_INDEX();
52 uint8_t read_index = GET_READ_INDEX();
53 SET_READ_INDEX(shared_index);
54 SET_SHARED_INDEX(read_index);
55 SET_DATA_AVAILABLE(false);
56 serial_link_unlock();
57 return object->buffer + object_size * shared_index;
58 }
59 else {
60 serial_link_unlock();
61 return NULL;
62 }
63}
64
65void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object) {
66 uint8_t write_index = GET_WRITE_INDEX();
67 return object->buffer + object_size * write_index;
68}
69
70void triple_buffer_end_write_internal(triple_buffer_object_t* object) {
71 serial_link_lock();
72 uint8_t shared_index = GET_SHARED_INDEX();
73 uint8_t write_index = GET_WRITE_INDEX();
74 SET_SHARED_INDEX(write_index);
75 SET_WRITE_INDEX(shared_index);
76 SET_DATA_AVAILABLE(true);
77 serial_link_unlock();
78}
diff --git a/quantum/serial_link/protocol/triple_buffered_object.h b/quantum/serial_link/protocol/triple_buffered_object.h
new file mode 100644
index 000000000..2e57db3f5
--- /dev/null
+++ b/quantum/serial_link/protocol/triple_buffered_object.h
@@ -0,0 +1,51 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H
26#define SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H
27
28#include <stdint.h>
29
30typedef struct {
31 uint8_t state;
32 uint8_t buffer[] __attribute__((aligned(4)));
33}triple_buffer_object_t;
34
35void triple_buffer_init(triple_buffer_object_t* object);
36
37#define triple_buffer_begin_write(object) \
38 (typeof(*object.buffer[0])*)triple_buffer_begin_write_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object)
39
40#define triple_buffer_end_write(object) \
41 triple_buffer_end_write_internal((triple_buffer_object_t*)object)
42
43#define triple_buffer_read(object) \
44 (typeof(*object.buffer[0])*)triple_buffer_read_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object)
45
46void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object);
47void triple_buffer_end_write_internal(triple_buffer_object_t* object);
48void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object);
49
50
51#endif
diff --git a/quantum/serial_link/system/serial_link.c b/quantum/serial_link/system/serial_link.c
new file mode 100644
index 000000000..75c7e77a7
--- /dev/null
+++ b/quantum/serial_link/system/serial_link.c
@@ -0,0 +1,265 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24#include "report.h"
25#include "host_driver.h"
26#include "serial_link/system/serial_link.h"
27#include "hal.h"
28#include "serial_link/protocol/byte_stuffer.h"
29#include "serial_link/protocol/transport.h"
30#include "serial_link/protocol/frame_router.h"
31#include "matrix.h"
32#include <stdbool.h>
33#include "print.h"
34#include "config.h"
35
36static event_source_t new_data_event;
37static bool serial_link_connected;
38static bool is_master = false;
39
40static uint8_t keyboard_leds(void);
41static void send_keyboard(report_keyboard_t *report);
42static void send_mouse(report_mouse_t *report);
43static void send_system(uint16_t data);
44static void send_consumer(uint16_t data);
45
46host_driver_t serial_driver = {
47 keyboard_leds,
48 send_keyboard,
49 send_mouse,
50 send_system,
51 send_consumer
52};
53
54// Define these in your Config.h file
55#ifndef SERIAL_LINK_BAUD
56#error "Serial link baud is not set"
57#endif
58
59#ifndef SERIAL_LINK_THREAD_PRIORITY
60#error "Serial link thread priority not set"
61#endif
62
63static SerialConfig config = {
64 .sc_speed = SERIAL_LINK_BAUD
65};
66
67//#define DEBUG_LINK_ERRORS
68
69static uint32_t read_from_serial(SerialDriver* driver, uint8_t link) {
70 const uint32_t buffer_size = 16;
71 uint8_t buffer[buffer_size];
72 uint32_t bytes_read = sdAsynchronousRead(driver, buffer, buffer_size);
73 uint8_t* current = buffer;
74 uint8_t* end = current + bytes_read;
75 while(current < end) {
76 byte_stuffer_recv_byte(link, *current);
77 current++;
78 }
79 return bytes_read;
80}
81
82static void print_error(char* str, eventflags_t flags, SerialDriver* driver) {
83#ifdef DEBUG_LINK_ERRORS
84 if (flags & SD_PARITY_ERROR) {
85 print(str);
86 print(" Parity error\n");
87 }
88 if (flags & SD_FRAMING_ERROR) {
89 print(str);
90 print(" Framing error\n");
91 }
92 if (flags & SD_OVERRUN_ERROR) {
93 print(str);
94 uint32_t size = qSpaceI(&(driver->iqueue));
95 xprintf(" Overrun error, queue size %d\n", size);
96
97 }
98 if (flags & SD_NOISE_ERROR) {
99 print(str);
100 print(" Noise error\n");
101 }
102 if (flags & SD_BREAK_DETECTED) {
103 print(str);
104 print(" Break detected\n");
105 }
106#else
107 (void)str;
108 (void)flags;
109 (void)driver;
110#endif
111}
112
113bool is_serial_link_master(void) {
114 return is_master;
115}
116
117// TODO: Optimize the stack size, this is probably way too big
118static THD_WORKING_AREA(serialThreadStack, 1024);
119static THD_FUNCTION(serialThread, arg) {
120 (void)arg;
121 event_listener_t new_data_listener;
122 event_listener_t sd1_listener;
123 event_listener_t sd2_listener;
124 chEvtRegister(&new_data_event, &new_data_listener, 0);
125 eventflags_t events = CHN_INPUT_AVAILABLE
126 | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED;
127 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1),
128 &sd1_listener,
129 EVENT_MASK(1),
130 events);
131 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2),
132 &sd2_listener,
133 EVENT_MASK(2),
134 events);
135 bool need_wait = false;
136 while(true) {
137 eventflags_t flags1 = 0;
138 eventflags_t flags2 = 0;
139 if (need_wait) {
140 eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000));
141 if (mask & EVENT_MASK(1)) {
142 flags1 = chEvtGetAndClearFlags(&sd1_listener);
143 print_error("DOWNLINK", flags1, &SD1);
144 }
145 if (mask & EVENT_MASK(2)) {
146 flags2 = chEvtGetAndClearFlags(&sd2_listener);
147 print_error("UPLINK", flags2, &SD2);
148 }
149 }
150
151 // Always stay as master, even if the USB goes into sleep mode
152 is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE;
153 router_set_master(is_master);
154
155 need_wait = true;
156 need_wait &= read_from_serial(&SD2, UP_LINK) == 0;
157 need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0;
158 update_transport();
159 }
160}
161
162void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
163 if (link == DOWN_LINK) {
164 sdWrite(&SD1, data, size);
165 }
166 else {
167 sdWrite(&SD2, data, size);
168 }
169}
170
171static systime_t last_update = 0;
172
173typedef struct {
174 matrix_row_t rows[MATRIX_ROWS];
175} matrix_object_t;
176
177static matrix_object_t last_matrix = {};
178
179SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t);
180MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool);
181
182static remote_object_t* remote_objects[] = {
183 REMOTE_OBJECT(serial_link_connected),
184 REMOTE_OBJECT(keyboard_matrix),
185};
186
187void init_serial_link(void) {
188 serial_link_connected = false;
189 init_serial_link_hal();
190 add_remote_objects(remote_objects, sizeof(remote_objects)/sizeof(remote_object_t*));
191 init_byte_stuffer();
192 sdStart(&SD1, &config);
193 sdStart(&SD2, &config);
194 chEvtObjectInit(&new_data_event);
195 (void)chThdCreateStatic(serialThreadStack, sizeof(serialThreadStack),
196 SERIAL_LINK_THREAD_PRIORITY, serialThread, NULL);
197}
198
199void matrix_set_remote(matrix_row_t* rows, uint8_t index);
200
201void serial_link_update(void) {
202 if (read_serial_link_connected()) {
203 serial_link_connected = true;
204 }
205
206 matrix_object_t matrix;
207 bool changed = false;
208 for(uint8_t i=0;i<MATRIX_ROWS;i++) {
209 matrix.rows[i] = matrix_get_row(i);
210 changed |= matrix.rows[i] != last_matrix.rows[i];
211 }
212
213 systime_t current_time = chVTGetSystemTimeX();
214 systime_t delta = current_time - last_update;
215 if (changed || delta > US2ST(1000)) {
216 last_update = current_time;
217 last_matrix = matrix;
218 matrix_object_t* m = begin_write_keyboard_matrix();
219 for(uint8_t i=0;i<MATRIX_ROWS;i++) {
220 m->rows[i] = matrix.rows[i];
221 }
222 end_write_keyboard_matrix();
223 *begin_write_serial_link_connected() = true;
224 end_write_serial_link_connected();
225 }
226
227 matrix_object_t* m = read_keyboard_matrix(0);
228 if (m) {
229 matrix_set_remote(m->rows, 0);
230 }
231}
232
233void signal_data_written(void) {
234 chEvtBroadcast(&new_data_event);
235}
236
237bool is_serial_link_connected(void) {
238 return serial_link_connected;
239}
240
241host_driver_t* get_serial_link_driver(void) {
242 return &serial_driver;
243}
244
245// NOTE: The driver does nothing, because the master handles everything
246uint8_t keyboard_leds(void) {
247 return 0;
248}
249
250void send_keyboard(report_keyboard_t *report) {
251 (void)report;
252}
253
254void send_mouse(report_mouse_t *report) {
255 (void)report;
256}
257
258void send_system(uint16_t data) {
259 (void)data;
260}
261
262void send_consumer(uint16_t data) {
263 (void)data;
264}
265
diff --git a/quantum/serial_link/system/serial_link.h b/quantum/serial_link/system/serial_link.h
new file mode 100644
index 000000000..351e03877
--- /dev/null
+++ b/quantum/serial_link/system/serial_link.h
@@ -0,0 +1,63 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef SERIAL_LINK_H
26#define SERIAL_LINK_H
27
28#include "host_driver.h"
29#include <stdbool.h>
30
31void init_serial_link(void);
32void init_serial_link_hal(void);
33bool is_serial_link_connected(void);
34bool is_serial_link_master(void);
35host_driver_t* get_serial_link_driver(void);
36void serial_link_update(void);
37
38#if defined(PROTOCOL_CHIBIOS)
39#include "ch.h"
40
41static inline void serial_link_lock(void) {
42 chSysLock();
43}
44
45static inline void serial_link_unlock(void) {
46 chSysUnlock();
47}
48
49void signal_data_written(void);
50
51#else
52
53inline void serial_link_lock(void) {
54}
55
56inline void serial_link_unlock(void) {
57}
58
59void signal_data_written(void);
60
61#endif
62
63#endif
diff --git a/quantum/serial_link/tests/Makefile b/quantum/serial_link/tests/Makefile
new file mode 100644
index 000000000..1b072c6f1
--- /dev/null
+++ b/quantum/serial_link/tests/Makefile
@@ -0,0 +1,61 @@
1# The MIT License (MIT)
2#
3# Copyright (c) 2016 Fred Sundvik
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23CC = gcc
24CFLAGS =
25INCLUDES = -I. -I../../
26LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared
27LDLIBS = -lcgreen
28UNITOBJ = $(BUILDDIR)/serialtest/unitobj
29DEPDIR = $(BUILDDIR)/serialtest/unit.d
30UNITTESTS = $(BUILDDIR)/serialtest/unittests
31DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
32EXT = .so
33UNAME := $(shell uname)
34ifneq (, $(findstring MINGW, $(UNAME)))
35 EXT = .dll
36endif
37ifneq (, $(findstring CYGWIN, $(UNAME)))
38 EXT = .dll
39endif
40
41SRC = $(wildcard *.c)
42TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC))
43$(shell mkdir -p $(DEPDIR) >/dev/null)
44
45test: $(TESTFILES)
46 @$(BUILDDIR)/cgreen/build-c/tools/cgreen-runner --color $(TESTFILES)
47
48$(UNITTESTS)/%$(EXT): $(UNITOBJ)/%.o
49 @mkdir -p $(UNITTESTS)
50 $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
51
52$(UNITOBJ)/%.o : %.c
53$(UNITOBJ)/%.o: %.c $(DEPDIR)/%.d
54 @mkdir -p $(UNITOBJ)
55 $(CC) $(CFLAGS) $(DEPFLAGS) $(INCLUDES) -c $< -o $@
56 @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
57
58$(DEPDIR)/%.d: ;
59.PRECIOUS: $(DEPDIR)/%.d
60
61-include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))) \ No newline at end of file
diff --git a/quantum/serial_link/tests/byte_stuffer_tests.cpp b/quantum/serial_link/tests/byte_stuffer_tests.cpp
new file mode 100644
index 000000000..ff49d727b
--- /dev/null
+++ b/quantum/serial_link/tests/byte_stuffer_tests.cpp
@@ -0,0 +1,483 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27#include <vector>
28#include <algorithm>
29extern "C" {
30#include "serial_link/protocol/byte_stuffer.h"
31#include "serial_link/protocol/frame_validator.h"
32#include "serial_link/protocol/physical.h"
33}
34
35using testing::_;
36using testing::ElementsAreArray;
37using testing::Args;
38
39class ByteStuffer : public ::testing::Test{
40public:
41 ByteStuffer() {
42 Instance = this;
43 init_byte_stuffer();
44 }
45
46 ~ByteStuffer() {
47 Instance = nullptr;
48 }
49
50 MOCK_METHOD3(validator_recv_frame, void (uint8_t link, uint8_t* data, uint16_t size));
51
52 void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
53 std::copy(data, data + size, std::back_inserter(sent_data));
54 }
55 std::vector<uint8_t> sent_data;
56
57 static ByteStuffer* Instance;
58};
59
60ByteStuffer* ByteStuffer::Instance = nullptr;
61
62extern "C" {
63 void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
64 ByteStuffer::Instance->validator_recv_frame(link, data, size);
65 }
66
67 void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
68 ByteStuffer::Instance->send_data(link, data, size);
69 }
70}
71
72TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
73 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
74 .Times(0);
75 byte_stuffer_recv_byte(0, 0);
76}
77
78TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
79 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
80 .Times(0);
81 byte_stuffer_recv_byte(0, 0xFF);
82}
83
84TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
85 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
86 .Times(0);
87 byte_stuffer_recv_byte(0, 0x4A);
88}
89
90TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
91 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
92 .Times(0);
93 byte_stuffer_recv_byte(0, 1);
94 byte_stuffer_recv_byte(0, 0);
95}
96
97TEST_F(ByteStuffer, receives_single_byte_valid_frame) {
98 uint8_t expected[] = {0x37};
99 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
100 .With(Args<1, 2>(ElementsAreArray(expected)));
101 byte_stuffer_recv_byte(0, 2);
102 byte_stuffer_recv_byte(0, 0x37);
103 byte_stuffer_recv_byte(0, 0);
104}
105TEST_F(ByteStuffer, receives_three_bytes_valid_frame) {
106 uint8_t expected[] = {0x37, 0x99, 0xFF};
107 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
108 .With(Args<1, 2>(ElementsAreArray(expected)));
109 byte_stuffer_recv_byte(0, 4);
110 byte_stuffer_recv_byte(0, 0x37);
111 byte_stuffer_recv_byte(0, 0x99);
112 byte_stuffer_recv_byte(0, 0xFF);
113 byte_stuffer_recv_byte(0, 0);
114}
115
116TEST_F(ByteStuffer, receives_single_zero_valid_frame) {
117 uint8_t expected[] = {0};
118 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
119 .With(Args<1, 2>(ElementsAreArray(expected)));
120 byte_stuffer_recv_byte(0, 1);
121 byte_stuffer_recv_byte(0, 1);
122 byte_stuffer_recv_byte(0, 0);
123}
124
125TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) {
126 uint8_t expected[] = {5, 0, 3, 0};
127 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
128 .With(Args<1, 2>(ElementsAreArray(expected)));
129 byte_stuffer_recv_byte(0, 2);
130 byte_stuffer_recv_byte(0, 5);
131 byte_stuffer_recv_byte(0, 2);
132 byte_stuffer_recv_byte(0, 3);
133 byte_stuffer_recv_byte(0, 1);
134 byte_stuffer_recv_byte(0, 0);
135}
136
137
138TEST_F(ByteStuffer, receives_two_valid_frames) {
139 uint8_t expected1[] = {5, 0};
140 uint8_t expected2[] = {3};
141 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
142 .With(Args<1, 2>(ElementsAreArray(expected1)));
143 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
144 .With(Args<1, 2>(ElementsAreArray(expected2)));
145 byte_stuffer_recv_byte(1, 2);
146 byte_stuffer_recv_byte(1, 5);
147 byte_stuffer_recv_byte(1, 1);
148 byte_stuffer_recv_byte(1, 0);
149 byte_stuffer_recv_byte(1, 2);
150 byte_stuffer_recv_byte(1, 3);
151 byte_stuffer_recv_byte(1, 0);
152}
153
154TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
155 uint8_t expected[] = {5, 7};
156 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
157 .With(Args<1, 2>(ElementsAreArray(expected)));
158 byte_stuffer_recv_byte(1, 3);
159 byte_stuffer_recv_byte(1, 1);
160 byte_stuffer_recv_byte(1, 0);
161 byte_stuffer_recv_byte(1, 3);
162 byte_stuffer_recv_byte(1, 5);
163 byte_stuffer_recv_byte(1, 7);
164 byte_stuffer_recv_byte(1, 0);
165}
166
167TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
168 uint8_t expected[] = {5, 7};
169 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
170 .With(Args<1, 2>(ElementsAreArray(expected)));
171 byte_stuffer_recv_byte(0, 2);
172 byte_stuffer_recv_byte(0, 9);
173 byte_stuffer_recv_byte(0, 4); // This should have been zero
174 byte_stuffer_recv_byte(0, 0);
175 byte_stuffer_recv_byte(0, 3);
176 byte_stuffer_recv_byte(0, 5);
177 byte_stuffer_recv_byte(0, 7);
178 byte_stuffer_recv_byte(0, 0);
179}
180
181TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
182 uint8_t expected[254];
183 int i;
184 for (i=0;i<254;i++) {
185 expected[i] = i + 1;
186 }
187 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
188 .With(Args<1, 2>(ElementsAreArray(expected)));
189 byte_stuffer_recv_byte(0, 0xFF);
190 for (i=0;i<254;i++) {
191 byte_stuffer_recv_byte(0, i+1);
192 }
193 byte_stuffer_recv_byte(0, 0);
194}
195
196TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
197 uint8_t expected[255];
198 int i;
199 for (i=0;i<254;i++) {
200 expected[i] = i + 1;
201 }
202 expected[254] = 7;
203 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
204 .With(Args<1, 2>(ElementsAreArray(expected)));
205 byte_stuffer_recv_byte(0, 0xFF);
206 for (i=0;i<254;i++) {
207 byte_stuffer_recv_byte(0, i+1);
208 }
209 byte_stuffer_recv_byte(0, 2);
210 byte_stuffer_recv_byte(0, 7);
211 byte_stuffer_recv_byte(0, 0);
212}
213
214TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
215 uint8_t expected[255];
216 int i;
217 for (i=0;i<254;i++) {
218 expected[i] = i + 1;
219 }
220 expected[254] = 0;
221 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
222 .With(Args<1, 2>(ElementsAreArray(expected)));
223 byte_stuffer_recv_byte(0, 0xFF);
224 for (i=0;i<254;i++) {
225 byte_stuffer_recv_byte(0, i+1);
226 }
227 byte_stuffer_recv_byte(0, 1);
228 byte_stuffer_recv_byte(0, 1);
229 byte_stuffer_recv_byte(0, 0);
230}
231
232TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) {
233 uint8_t expected[515];
234 int i;
235 int j;
236 for (j=0;j<2;j++) {
237 for (i=0;i<254;i++) {
238 expected[i+254*j] = i + 1;
239 }
240 }
241 for (i=0;i<7;i++) {
242 expected[254*2+i] = i + 1;
243 }
244 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
245 .With(Args<1, 2>(ElementsAreArray(expected)));
246 byte_stuffer_recv_byte(0, 0xFF);
247 for (i=0;i<254;i++) {
248 byte_stuffer_recv_byte(0, i+1);
249 }
250 byte_stuffer_recv_byte(0, 0xFF);
251 for (i=0;i<254;i++) {
252 byte_stuffer_recv_byte(0, i+1);
253 }
254 byte_stuffer_recv_byte(0, 8);
255 byte_stuffer_recv_byte(0, 1);
256 byte_stuffer_recv_byte(0, 2);
257 byte_stuffer_recv_byte(0, 3);
258 byte_stuffer_recv_byte(0, 4);
259 byte_stuffer_recv_byte(0, 5);
260 byte_stuffer_recv_byte(0, 6);
261 byte_stuffer_recv_byte(0, 7);
262 byte_stuffer_recv_byte(0, 0);
263}
264
265TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
266 uint8_t expected[MAX_FRAME_SIZE] = {};
267 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
268 .With(Args<1, 2>(ElementsAreArray(expected)));
269 int i;
270 byte_stuffer_recv_byte(0, 1);
271 for(i=0;i<MAX_FRAME_SIZE;i++) {
272 byte_stuffer_recv_byte(0, 1);
273 }
274 byte_stuffer_recv_byte(0, 0);
275}
276
277TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
278 uint8_t expected[1] = {0};
279 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
280 .Times(0);
281 int i;
282 byte_stuffer_recv_byte(0, 1);
283 for(i=0;i<MAX_FRAME_SIZE;i++) {
284 byte_stuffer_recv_byte(0, 1);
285 }
286 byte_stuffer_recv_byte(0, 1);
287 byte_stuffer_recv_byte(0, 0);
288}
289
290TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
291 uint8_t expected[1] = {1};
292 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
293 .With(Args<1, 2>(ElementsAreArray(expected)));
294 int i;
295 byte_stuffer_recv_byte(0, 1);
296 for(i=0;i<MAX_FRAME_SIZE;i++) {
297 byte_stuffer_recv_byte(0, 1);
298 }
299 byte_stuffer_recv_byte(0, 2);
300 byte_stuffer_recv_byte(0, 1);
301 byte_stuffer_recv_byte(0, 0);
302}
303
304TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
305 EXPECT_EQ(sent_data.size(), 0);
306 byte_stuffer_send_frame(0, NULL, 0);
307}
308
309TEST_F(ByteStuffer, send_one_byte_frame) {
310 uint8_t data[] = {5};
311 byte_stuffer_send_frame(1, data, 1);
312 uint8_t expected[] = {2, 5, 0};
313 EXPECT_THAT(sent_data, ElementsAreArray(expected));
314}
315
316TEST_F(ByteStuffer, sends_two_byte_frame) {
317 uint8_t data[] = {5, 0x77};
318 byte_stuffer_send_frame(0, data, 2);
319 uint8_t expected[] = {3, 5, 0x77, 0};
320 EXPECT_THAT(sent_data, ElementsAreArray(expected));
321}
322
323TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) {
324 uint8_t data[] = {0};
325 byte_stuffer_send_frame(0, data, 1);
326 uint8_t expected[] = {1, 1, 0};
327 EXPECT_THAT(sent_data, ElementsAreArray(expected));
328}
329
330TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
331 uint8_t data[] = {0, 9};
332 byte_stuffer_send_frame(1, data, 2);
333 uint8_t expected[] = {1, 2, 9, 0};
334 EXPECT_THAT(sent_data, ElementsAreArray(expected));
335}
336
337TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
338 uint8_t data[] = {9, 0};
339 byte_stuffer_send_frame(1, data, 2);
340 uint8_t expected[] = {2, 9, 1, 0};
341 EXPECT_THAT(sent_data, ElementsAreArray(expected));
342}
343
344TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
345 uint8_t data[] = {9, 0, 0x68};
346 byte_stuffer_send_frame(0, data, 3);
347 uint8_t expected[] = {2, 9, 2, 0x68, 0};
348 EXPECT_THAT(sent_data, ElementsAreArray(expected));
349}
350
351TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
352 uint8_t data[] = {0, 0x55, 0};
353 byte_stuffer_send_frame(0, data, 3);
354 uint8_t expected[] = {1, 2, 0x55, 1, 0};
355 EXPECT_THAT(sent_data, ElementsAreArray(expected));
356}
357
358TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
359 uint8_t data[] = {0, 0, 0};
360 byte_stuffer_send_frame(0, data, 3);
361 uint8_t expected[] = {1, 1, 1, 1, 0};
362 EXPECT_THAT(sent_data, ElementsAreArray(expected));
363}
364
365TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) {
366 uint8_t data[254];
367 int i;
368 for(i=0;i<254;i++) {
369 data[i] = i + 1;
370 }
371 byte_stuffer_send_frame(0, data, 254);
372 uint8_t expected[256];
373 expected[0] = 0xFF;
374 for(i=1;i<255;i++) {
375 expected[i] = i;
376 }
377 expected[255] = 0;
378 EXPECT_THAT(sent_data, ElementsAreArray(expected));
379}
380
381TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) {
382 uint8_t data[255];
383 int i;
384 for(i=0;i<255;i++) {
385 data[i] = i + 1;
386 }
387 byte_stuffer_send_frame(0, data, 255);
388 uint8_t expected[258];
389 expected[0] = 0xFF;
390 for(i=1;i<255;i++) {
391 expected[i] = i;
392 }
393 expected[255] = 2;
394 expected[256] = 255;
395 expected[257] = 0;
396 EXPECT_THAT(sent_data, ElementsAreArray(expected));
397}
398
399TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
400 uint8_t data[255];
401 int i;
402 for(i=0;i<254;i++) {
403 data[i] = i + 1;
404 }
405 data[254] = 0;
406 byte_stuffer_send_frame(0, data, 255);
407 uint8_t expected[258];
408 expected[0] = 0xFF;
409 for(i=1;i<255;i++) {
410 expected[i] = i;
411 }
412 expected[255] = 1;
413 expected[256] = 1;
414 expected[257] = 0;
415 EXPECT_THAT(sent_data, ElementsAreArray(expected));
416}
417
418TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
419 uint8_t original_data[] = { 1, 2, 3};
420 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
421 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
422 .With(Args<1, 2>(ElementsAreArray(original_data)));
423 int i;
424 for(auto& d : sent_data) {
425 byte_stuffer_recv_byte(1, d);
426 }
427}
428
429TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
430 uint8_t original_data[] = { 1, 0, 3, 0, 0, 9};
431 byte_stuffer_send_frame(1, original_data, sizeof(original_data));
432 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
433 .With(Args<1, 2>(ElementsAreArray(original_data)));
434 int i;
435 for(auto& d : sent_data) {
436 byte_stuffer_recv_byte(1, d);
437 }
438}
439
440TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
441 uint8_t original_data[254];
442 int i;
443 for(i=0;i<254;i++) {
444 original_data[i] = i + 1;
445 }
446 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
447 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
448 .With(Args<1, 2>(ElementsAreArray(original_data)));
449 for(auto& d : sent_data) {
450 byte_stuffer_recv_byte(1, d);
451 }
452}
453
454TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
455 uint8_t original_data[256];
456 int i;
457 for(i=0;i<254;i++) {
458 original_data[i] = i + 1;
459 }
460 original_data[254] = 22;
461 original_data[255] = 23;
462 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
463 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
464 .With(Args<1, 2>(ElementsAreArray(original_data)));
465 for(auto& d : sent_data) {
466 byte_stuffer_recv_byte(1, d);
467 }
468}
469
470TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
471 uint8_t original_data[255];
472 int i;
473 for(i=0;i<254;i++) {
474 original_data[i] = i + 1;
475 }
476 original_data[254] = 0;
477 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
478 EXPECT_CALL(*this, validator_recv_frame(_, _, _))
479 .With(Args<1, 2>(ElementsAreArray(original_data)));
480 for(auto& d : sent_data) {
481 byte_stuffer_recv_byte(1, d);
482 }
483}
diff --git a/quantum/serial_link/tests/frame_router_tests.cpp b/quantum/serial_link/tests/frame_router_tests.cpp
new file mode 100644
index 000000000..2bd5bf830
--- /dev/null
+++ b/quantum/serial_link/tests/frame_router_tests.cpp
@@ -0,0 +1,229 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27#include <array>
28extern "C" {
29 #include "serial_link/protocol/transport.h"
30 #include "serial_link/protocol/byte_stuffer.h"
31 #include "serial_link/protocol/frame_router.h"
32}
33
34using testing::_;
35using testing::ElementsAreArray;
36using testing::Args;
37
38class FrameRouter : public testing::Test {
39public:
40 FrameRouter() :
41 current_router_buffer(nullptr)
42 {
43 Instance = this;
44 init_byte_stuffer();
45 }
46
47 ~FrameRouter() {
48 Instance = nullptr;
49 }
50
51 void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
52 auto& buffer = current_router_buffer->send_buffers[link];
53 std::copy(data, data + size, std::back_inserter(buffer));
54 }
55
56 void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
57 int i;
58 for(i=0;i<size;i++) {
59 byte_stuffer_recv_byte(link, data[i]);
60 }
61 }
62
63 void activate_router(uint8_t num) {
64 current_router_buffer = router_buffers + num;
65 router_set_master(num==0);
66 }
67
68 void simulate_transport(uint8_t from, uint8_t to) {
69 activate_router(to);
70 if (from > to) {
71 receive_data(DOWN_LINK,
72 router_buffers[from].send_buffers[UP_LINK].data(),
73 router_buffers[from].send_buffers[UP_LINK].size());
74 }
75 else if(to > from) {
76 receive_data(UP_LINK,
77 router_buffers[from].send_buffers[DOWN_LINK].data(),
78 router_buffers[from].send_buffers[DOWN_LINK].size());
79 }
80 }
81
82 MOCK_METHOD3(transport_recv_frame, void (uint8_t from, uint8_t* data, uint16_t size));
83
84 std::vector<uint8_t> received_data;
85
86 struct router_buffer {
87 std::vector<uint8_t> send_buffers[2];
88 };
89
90 router_buffer router_buffers[8];
91 router_buffer* current_router_buffer;
92
93 static FrameRouter* Instance;
94};
95
96FrameRouter* FrameRouter::Instance = nullptr;
97
98
99typedef struct {
100 std::array<uint8_t, 4> data;
101 uint8_t extra[16];
102} frame_buffer_t;
103
104
105extern "C" {
106 void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
107 FrameRouter::Instance->send_data(link, data, size);
108 }
109
110
111 void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
112 FrameRouter::Instance->transport_recv_frame(from, data, size);
113 }
114}
115
116TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) {
117 frame_buffer_t data;
118 data.data = {0xAB, 0x70, 0x55, 0xBB};
119 activate_router(0);
120 router_send_frame(0xFF, (uint8_t*)&data, 4);
121 EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
122 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
123 EXPECT_CALL(*this, transport_recv_frame(0, _, _))
124 .With(Args<1, 2>(ElementsAreArray(data.data)));
125 simulate_transport(0, 1);
126 EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
127 EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
128
129 EXPECT_CALL(*this, transport_recv_frame(0, _, _))
130 .With(Args<1, 2>(ElementsAreArray(data.data)));
131 simulate_transport(1, 2);
132 EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
133 EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
134}
135
136TEST_F(FrameRouter, master_send_is_received_by_targets) {
137 frame_buffer_t data;
138 data.data = {0xAB, 0x70, 0x55, 0xBB};
139 activate_router(0);
140 router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
141 EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
142 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
143
144 simulate_transport(0, 1);
145 EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
146 EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
147
148 EXPECT_CALL(*this, transport_recv_frame(0, _, _))
149 .With(Args<1, 2>(ElementsAreArray(data.data)));
150 simulate_transport(1, 2);
151 EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
152 EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
153
154 EXPECT_CALL(*this, transport_recv_frame(0, _, _))
155 .With(Args<1, 2>(ElementsAreArray(data.data)));
156 simulate_transport(2, 3);
157 EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0);
158 EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0);
159}
160
161TEST_F(FrameRouter, first_link_sends_to_master) {
162 frame_buffer_t data;
163 data.data = {0xAB, 0x70, 0x55, 0xBB};
164 activate_router(1);
165 router_send_frame(0, (uint8_t*)&data, 4);
166 EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
167 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
168
169 EXPECT_CALL(*this, transport_recv_frame(1, _, _))
170 .With(Args<1, 2>(ElementsAreArray(data.data)));
171 simulate_transport(1, 0);
172 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
173 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
174}
175
176TEST_F(FrameRouter, second_link_sends_to_master) {
177 frame_buffer_t data;
178 data.data = {0xAB, 0x70, 0x55, 0xBB};
179 activate_router(2);
180 router_send_frame(0, (uint8_t*)&data, 4);
181 EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0);
182 EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
183
184 simulate_transport(2, 1);
185 EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
186 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
187
188 EXPECT_CALL(*this, transport_recv_frame(2, _, _))
189 .With(Args<1, 2>(ElementsAreArray(data.data)));
190 simulate_transport(1, 0);
191 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
192 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
193}
194
195TEST_F(FrameRouter, master_sends_to_master_does_nothing) {
196 frame_buffer_t data;
197 data.data = {0xAB, 0x70, 0x55, 0xBB};
198 activate_router(0);
199 router_send_frame(0, (uint8_t*)&data, 4);
200 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
201 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
202}
203
204TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) {
205 frame_buffer_t data;
206 data.data = {0xAB, 0x70, 0x55, 0xBB};
207 activate_router(1);
208 router_send_frame(2, (uint8_t*)&data, 4);
209 EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
210 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
211}
212
213TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) {
214 frame_buffer_t data;
215 data.data = {0xAB, 0x70, 0x55, 0xBB};
216 activate_router(1);
217 router_send_frame(0, (uint8_t*)&data, 4);
218 EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
219 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
220
221 EXPECT_CALL(*this, transport_recv_frame(_, _, _))
222 .Times(0);
223 activate_router(0);
224 receive_data(UP_LINK,
225 router_buffers[1].send_buffers[UP_LINK].data(),
226 router_buffers[1].send_buffers[UP_LINK].size());
227 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
228 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
229}
diff --git a/quantum/serial_link/tests/frame_validator_tests.cpp b/quantum/serial_link/tests/frame_validator_tests.cpp
new file mode 100644
index 000000000..9223af83b
--- /dev/null
+++ b/quantum/serial_link/tests/frame_validator_tests.cpp
@@ -0,0 +1,115 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27extern "C" {
28#include "serial_link/protocol/frame_validator.h"
29}
30
31using testing::_;
32using testing::ElementsAreArray;
33using testing::Args;
34
35class FrameValidator : public testing::Test {
36public:
37 FrameValidator() {
38 Instance = this;
39 }
40
41 ~FrameValidator() {
42 Instance = nullptr;
43 }
44
45 MOCK_METHOD3(route_incoming_frame, void (uint8_t link, uint8_t* data, uint16_t size));
46 MOCK_METHOD3(byte_stuffer_send_frame, void (uint8_t link, uint8_t* data, uint16_t size));
47
48 static FrameValidator* Instance;
49};
50
51FrameValidator* FrameValidator::Instance = nullptr;
52
53extern "C" {
54void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
55 FrameValidator::Instance->route_incoming_frame(link, data, size);
56}
57
58void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
59 FrameValidator::Instance->byte_stuffer_send_frame(link, data, size);
60}
61}
62
63TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) {
64 EXPECT_CALL(*this, route_incoming_frame(_, _, _))
65 .Times(0);
66 uint8_t data[] = {1, 2};
67 validator_recv_frame(0, 0, 1);
68 validator_recv_frame(0, data, 2);
69 validator_recv_frame(0, data, 3);
70 validator_recv_frame(0, data, 4);
71}
72
73TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) {
74 uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
75 EXPECT_CALL(*this, route_incoming_frame(_, _, _))
76 .With(Args<1, 2>(ElementsAreArray(data, 1)));
77 validator_recv_frame(0, data, 5);
78}
79
80TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
81 uint8_t data[] = {0x44, 0, 0, 0, 0};
82 EXPECT_CALL(*this, route_incoming_frame(_, _, _))
83 .Times(0);
84 validator_recv_frame(1, data, 5);
85}
86
87TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) {
88 uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
89 EXPECT_CALL(*this, route_incoming_frame(_, _, _))
90 .With(Args<1, 2>(ElementsAreArray(data, 4)));
91 validator_recv_frame(1, data, 8);
92}
93
94TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) {
95 uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
96 EXPECT_CALL(*this, route_incoming_frame(_, _, _))
97 .With(Args<1, 2>(ElementsAreArray(data, 5)));
98 validator_recv_frame(0, data, 9);
99}
100
101TEST_F(FrameValidator, sends_one_byte_with_correct_crc) {
102 uint8_t original[] = {0x44, 0, 0, 0, 0};
103 uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
104 EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _))
105 .With(Args<1, 2>(ElementsAreArray(expected)));
106 validator_send_frame(0, original, 1);
107}
108
109TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) {
110 uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
111 uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
112 EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _))
113 .With(Args<1, 2>(ElementsAreArray(expected)));
114 validator_send_frame(0, original, 5);
115}
diff --git a/quantum/serial_link/tests/rules.mk b/quantum/serial_link/tests/rules.mk
new file mode 100644
index 000000000..b81515bc5
--- /dev/null
+++ b/quantum/serial_link/tests/rules.mk
@@ -0,0 +1,22 @@
1serial_link_byte_stuffer_SRC :=\
2 $(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \
3 $(SERIAL_PATH)/protocol/byte_stuffer.c
4
5serial_link_frame_validator_SRC := \
6 $(SERIAL_PATH)/tests/frame_validator_tests.cpp \
7 $(SERIAL_PATH)/protocol/frame_validator.c
8
9serial_link_frame_router_SRC := \
10 $(SERIAL_PATH)/tests/frame_router_tests.cpp \
11 $(SERIAL_PATH)/protocol/byte_stuffer.c \
12 $(SERIAL_PATH)/protocol/frame_validator.c \
13 $(SERIAL_PATH)/protocol/frame_router.c
14
15serial_link_triple_buffered_object_SRC := \
16 $(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \
17 $(SERIAL_PATH)/protocol/triple_buffered_object.c
18
19serial_link_transport_SRC := \
20 $(SERIAL_PATH)/tests/transport_tests.cpp \
21 $(SERIAL_PATH)/protocol/transport.c \
22 $(SERIAL_PATH)/protocol/triple_buffered_object.c
diff --git a/quantum/serial_link/tests/testlist.mk b/quantum/serial_link/tests/testlist.mk
new file mode 100644
index 000000000..a80e88884
--- /dev/null
+++ b/quantum/serial_link/tests/testlist.mk
@@ -0,0 +1,6 @@
1TEST_LIST +=\
2 serial_link_byte_stuffer\
3 serial_link_frame_validator\
4 serial_link_frame_router\
5 serial_link_triple_buffered_object\
6 serial_link_transport \ No newline at end of file
diff --git a/quantum/serial_link/tests/transport_tests.cpp b/quantum/serial_link/tests/transport_tests.cpp
new file mode 100644
index 000000000..21b7b165f
--- /dev/null
+++ b/quantum/serial_link/tests/transport_tests.cpp
@@ -0,0 +1,188 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27
28using testing::_;
29using testing::ElementsAreArray;
30using testing::Args;
31
32extern "C" {
33#include "serial_link/protocol/transport.h"
34}
35
36struct test_object1 {
37 uint32_t test;
38};
39
40struct test_object2 {
41 uint32_t test1;
42 uint32_t test2;
43};
44
45MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1);
46MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1);
47SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1);
48
49static remote_object_t* test_remote_objects[] = {
50 REMOTE_OBJECT(master_to_slave),
51 REMOTE_OBJECT(master_to_single_slave),
52 REMOTE_OBJECT(slave_to_master),
53};
54
55class Transport : public testing::Test {
56public:
57 Transport() {
58 Instance = this;
59 add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
60 }
61
62 ~Transport() {
63 Instance = nullptr;
64 reinitialize_serial_link_transport();
65 }
66
67 MOCK_METHOD0(signal_data_written, void ());
68 MOCK_METHOD1(router_send_frame, void (uint8_t destination));
69
70 void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
71 router_send_frame(destination);
72 std::copy(data, data + size, std::back_inserter(sent_data));
73 }
74
75 static Transport* Instance;
76
77 std::vector<uint8_t> sent_data;
78};
79
80Transport* Transport::Instance = nullptr;
81
82extern "C" {
83void signal_data_written(void) {
84 Transport::Instance->signal_data_written();
85}
86
87void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
88 Transport::Instance->router_send_frame(destination, data, size);
89}
90}
91
92TEST_F(Transport, write_to_local_signals_an_event) {
93 begin_write_master_to_slave();
94 EXPECT_CALL(*this, signal_data_written());
95 end_write_master_to_slave();
96 begin_write_slave_to_master();
97 EXPECT_CALL(*this, signal_data_written());
98 end_write_slave_to_master();
99 begin_write_master_to_single_slave(1);
100 EXPECT_CALL(*this, signal_data_written());
101 end_write_master_to_single_slave(1);
102}
103
104TEST_F(Transport, writes_from_master_to_all_slaves) {
105 update_transport();
106 test_object1* obj = begin_write_master_to_slave();
107 obj->test = 5;
108 EXPECT_CALL(*this, signal_data_written());
109 end_write_master_to_slave();
110 EXPECT_CALL(*this, router_send_frame(0xFF));
111 update_transport();
112 transport_recv_frame(0, sent_data.data(), sent_data.size());
113 test_object1* obj2 = read_master_to_slave();
114 EXPECT_NE(obj2, nullptr);
115 EXPECT_EQ(obj2->test, 5);
116}
117
118TEST_F(Transport, writes_from_slave_to_master) {
119 update_transport();
120 test_object1* obj = begin_write_slave_to_master();
121 obj->test = 7;
122 EXPECT_CALL(*this, signal_data_written());
123 end_write_slave_to_master();
124 EXPECT_CALL(*this, router_send_frame(0));
125 update_transport();
126 transport_recv_frame(3, sent_data.data(), sent_data.size());
127 test_object1* obj2 = read_slave_to_master(2);
128 EXPECT_EQ(read_slave_to_master(0), nullptr);
129 EXPECT_NE(obj2, nullptr);
130 EXPECT_EQ(obj2->test, 7);
131}
132
133TEST_F(Transport, writes_from_master_to_single_slave) {
134 update_transport();
135 test_object1* obj = begin_write_master_to_single_slave(3);
136 obj->test = 7;
137 EXPECT_CALL(*this, signal_data_written());
138 end_write_master_to_single_slave(3);
139 EXPECT_CALL(*this, router_send_frame(4));
140 update_transport();
141 transport_recv_frame(0, sent_data.data(), sent_data.size());
142 test_object1* obj2 = read_master_to_single_slave();
143 EXPECT_NE(obj2, nullptr);
144 EXPECT_EQ(obj2->test, 7);
145}
146
147TEST_F(Transport, ignores_object_with_invalid_id) {
148 update_transport();
149 test_object1* obj = begin_write_master_to_single_slave(3);
150 obj->test = 7;
151 EXPECT_CALL(*this, signal_data_written());
152 end_write_master_to_single_slave(3);
153 EXPECT_CALL(*this, router_send_frame(4));
154 update_transport();
155 sent_data[sent_data.size() - 1] = 44;
156 transport_recv_frame(0, sent_data.data(), sent_data.size());
157 test_object1* obj2 = read_master_to_single_slave();
158 EXPECT_EQ(obj2, nullptr);
159}
160
161TEST_F(Transport, ignores_object_with_size_too_small) {
162 update_transport();
163 test_object1* obj = begin_write_master_to_slave();
164 obj->test = 7;
165 EXPECT_CALL(*this, signal_data_written());
166 end_write_master_to_slave();
167 EXPECT_CALL(*this, router_send_frame(_));
168 update_transport();
169 sent_data[sent_data.size() - 2] = 0;
170 transport_recv_frame(0, sent_data.data(), sent_data.size() - 1);
171 test_object1* obj2 = read_master_to_slave();
172 EXPECT_EQ(obj2, nullptr);
173}
174
175TEST_F(Transport, ignores_object_with_size_too_big) {
176 update_transport();
177 test_object1* obj = begin_write_master_to_slave();
178 obj->test = 7;
179 EXPECT_CALL(*this, signal_data_written());
180 end_write_master_to_slave();
181 EXPECT_CALL(*this, router_send_frame(_));
182 update_transport();
183 sent_data.resize(sent_data.size() + 22);
184 sent_data[sent_data.size() - 1] = 0;
185 transport_recv_frame(0, sent_data.data(), sent_data.size());
186 test_object1* obj2 = read_master_to_slave();
187 EXPECT_EQ(obj2, nullptr);
188}
diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.cpp b/quantum/serial_link/tests/triple_buffered_object_tests.cpp
new file mode 100644
index 000000000..7724bbee9
--- /dev/null
+++ b/quantum/serial_link/tests/triple_buffered_object_tests.cpp
@@ -0,0 +1,84 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26extern "C" {
27#include "serial_link/protocol/triple_buffered_object.h"
28}
29
30struct test_object{
31 uint8_t state;
32 uint32_t buffer[3];
33};
34
35test_object test_object;
36
37class TripleBufferedObject : public testing::Test {
38public:
39 TripleBufferedObject() {
40 triple_buffer_init((triple_buffer_object_t*)&test_object);
41 }
42};
43
44TEST_F(TripleBufferedObject, writes_and_reads_object) {
45 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
46 triple_buffer_end_write(&test_object);
47 EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC);
48}
49
50TEST_F(TripleBufferedObject, does_not_read_empty) {
51 EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
52}
53
54TEST_F(TripleBufferedObject, writes_twice_and_reads_object) {
55 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
56 triple_buffer_end_write(&test_object);
57 *triple_buffer_begin_write(&test_object) = 0x44778899;
58 triple_buffer_end_write(&test_object);
59 EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899);
60}
61
62TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
63 *triple_buffer_begin_write(&test_object) = 1;
64 triple_buffer_end_write(&test_object);
65 uint32_t* read = triple_buffer_read(&test_object);
66 *triple_buffer_begin_write(&test_object) = 2;
67 triple_buffer_end_write(&test_object);
68 EXPECT_EQ(*read, 1);
69 EXPECT_EQ(*triple_buffer_read(&test_object), 2);
70 EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
71}
72
73TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
74 *triple_buffer_begin_write(&test_object) = 1;
75 triple_buffer_end_write(&test_object);
76 uint32_t* read = triple_buffer_read(&test_object);
77 *triple_buffer_begin_write(&test_object) = 2;
78 triple_buffer_end_write(&test_object);
79 *triple_buffer_begin_write(&test_object) = 3;
80 triple_buffer_end_write(&test_object);
81 EXPECT_EQ(*read, 1);
82 EXPECT_EQ(*triple_buffer_read(&test_object), 3);
83 EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
84}
diff --git a/quantum/template/Makefile b/quantum/template/Makefile
index 2efa69138..4e2a6f00f 100644
--- a/quantum/template/Makefile
+++ b/quantum/template/Makefile
@@ -1,139 +1,3 @@
1#---------------------------------------------------------------------------- 1ifndef MAKEFILE_INCLUDED
2# On command line: 2 include ../../Makefile
3# 3endif \ No newline at end of file
4# make all = Make software.
5#
6# make clean = Clean out built project files.
7#
8# make coff = Convert ELF to AVR COFF.
9#
10# make extcoff = Convert ELF to AVR Extended COFF.
11#
12# make program = Download the hex file to the device.
13# Please customize your programmer settings(PROGRAM_CMD)
14#
15# make teensy = Download the hex file to the device, using teensy_loader_cli.
16# (must have teensy_loader_cli installed).
17#
18# make dfu = Download the hex file to the device, using dfu-programmer (must
19# have dfu-programmer installed).
20#
21# make flip = Download the hex file to the device, using Atmel FLIP (must
22# have Atmel FLIP installed).
23#
24# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
25# (must have dfu-programmer installed).
26#
27# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
28# (must have Atmel FLIP installed).
29#
30# make debug = Start either simulavr or avarice as specified for debugging,
31# with avr-gdb or avr-insight as the front end for debugging.
32#
33# make filename.s = Just compile filename.c into the assembler code only.
34#
35# make filename.i = Create a preprocessed source file for use in submitting
36# bug reports to the GCC project.
37#
38# To rebuild project do "make clean" then "make all".
39#----------------------------------------------------------------------------
40
41# Target file name (without extension).
42TARGET = %KEYBOARD%
43
44
45# Directory common source filess exist
46TOP_DIR = ../..
47TMK_DIR = ../../tmk_core
48
49# Directory keyboard dependent files exist
50TARGET_DIR = .
51
52# # project specific files
53SRC = %KEYBOARD%.c
54
55ifdef KEYMAP
56 SRC := keymaps/$(KEYMAP).c $(SRC)
57else
58 SRC := keymaps/default.c $(SRC)
59endif
60
61CONFIG_H = config.h
62
63# MCU name
64#MCU = at90usb1287
65MCU = atmega32u4
66
67# Processor frequency.
68# This will define a symbol, F_CPU, in all source code files equal to the
69# processor frequency in Hz. You can then use this symbol in your source code to
70# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
71# automatically to create a 32-bit value in your source code.
72#
73# This will be an integer division of F_USB below, as it is sourced by
74# F_USB after it has run through any CPU prescalers. Note that this value
75# does not *change* the processor frequency - it should merely be updated to
76# reflect the processor speed set externally so that the code can use accurate
77# software delays.
78F_CPU = 16000000
79
80
81#
82# LUFA specific
83#
84# Target architecture (see library "Board Types" documentation).
85ARCH = AVR8
86
87# Input clock frequency.
88# This will define a symbol, F_USB, in all source code files equal to the
89# input clock frequency (before any prescaling is performed) in Hz. This value may
90# differ from F_CPU if prescaling is used on the latter, and is required as the
91# raw input clock is fed directly to the PLL sections of the AVR for high speed
92# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
93# at the end, this will be done automatically to create a 32-bit value in your
94# source code.
95#
96# If no clock division is performed on the input clock inside the AVR (via the
97# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
98F_USB = $(F_CPU)
99
100# Interrupt driven control endpoint task(+60)
101OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
102
103
104# Boot Section Size in *bytes*
105# Teensy halfKay 512
106# Teensy++ halfKay 1024
107# Atmel DFU loader 4096
108# LUFA bootloader 4096
109# USBaspLoader 2048
110OPT_DEFS += -DBOOTLOADER_SIZE=512
111
112
113# Build Options
114# comment out to disable the options.
115#
116BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
117MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
118EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
119CONSOLE_ENABLE = yes # Console for debug(+400)
120COMMAND_ENABLE = yes # Commands for debug and configuration
121# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
122# SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
123# NKRO_ENABLE = yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
124# BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
125# MIDI_ENABLE = YES # MIDI controls
126# UNICODE_ENABLE = YES # Unicode
127# BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID
128
129
130# Optimize size but this may cause error "relocation truncated to fit"
131#EXTRALDFLAGS = -Wl,--relax
132
133# Search Path
134VPATH += $(TARGET_DIR)
135VPATH += $(TOP_DIR)
136VPATH += $(TMK_DIR)
137
138include $(TOP_DIR)/quantum/quantum.mk
139
diff --git a/quantum/template/config.h b/quantum/template/config.h
index 7d6149f43..b02f0c7eb 100644
--- a/quantum/template/config.h
+++ b/quantum/template/config.h
@@ -32,34 +32,115 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
32#define MATRIX_ROWS 2 32#define MATRIX_ROWS 2
33#define MATRIX_COLS 3 33#define MATRIX_COLS 3
34 34
35// Planck PCB default pin-out 35/*
36// Change this to how you wired your keyboard 36 * Keyboard Matrix Assignments
37// COLS: Left to right, ROWS: Top to bottom 37 *
38#define COLS (int []){ F1, F0, B0 } 38 * Change this to how you wired your keyboard
39#define ROWS (int []){ D0, D5 } 39 * COLS: AVR pins used for columns, left to right
40 * ROWS: AVR pins used for rows, top to bottom
41 * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
42 * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
43 *
44*/
45#define MATRIX_ROW_PINS { D0, D5 }
46#define MATRIX_COL_PINS { F1, F0, B0 }
47#define UNUSED_PINS
40 48
41/* COL2ROW or ROW2COL */ 49/* COL2ROW or ROW2COL */
42#define DIODE_DIRECTION COL2ROW 50#define DIODE_DIRECTION COL2ROW
51
52// #define BACKLIGHT_PIN B7
53// #define BACKLIGHT_BREATHING
54// #define BACKLIGHT_LEVELS 3
55
43 56
44/* define if matrix has ghost */ 57/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
58#define DEBOUNCING_DELAY 5
59
60/* define if matrix has ghost (lacks anti-ghosting diodes) */
45//#define MATRIX_HAS_GHOST 61//#define MATRIX_HAS_GHOST
46 62
47/* number of backlight levels */ 63/* number of backlight levels */
48#define BACKLIGHT_LEVELS 3
49
50/* Set 0 if debouncing isn't needed */
51#define DEBOUNCE 5
52 64
53/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ 65/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
54#define LOCKING_SUPPORT_ENABLE 66#define LOCKING_SUPPORT_ENABLE
55/* Locking resynchronize hack */ 67/* Locking resynchronize hack */
56#define LOCKING_RESYNC_ENABLE 68#define LOCKING_RESYNC_ENABLE
57 69
58/* key combination for command */ 70/*
71 * Force NKRO
72 *
73 * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
74 * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
75 * makefile for this to work.)
76 *
77 * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
78 * until the next keyboard reset.
79 *
80 * NKRO may prevent your keystrokes from being detected in the BIOS, but it is
81 * fully operational during normal computer usage.
82 *
83 * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
84 * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
85 * bootmagic, NKRO mode will always be enabled until it is toggled again during a
86 * power-up.
87 *
88 */
89//#define FORCE_NKRO
90
91/*
92 * Magic Key Options
93 *
94 * Magic keys are hotkey commands that allow control over firmware functions of
95 * the keyboard. They are best used in combination with the HID Listen program,
96 * found here: https://www.pjrc.com/teensy/hid_listen.html
97 *
98 * The options below allow the magic key functionality to be changed. This is
99 * useful if your keyboard/keypad is missing keys and you want magic key support.
100 *
101 */
102
103/* key combination for magic key command */
59#define IS_COMMAND() ( \ 104#define IS_COMMAND() ( \
60 keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ 105 keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
61) 106)
62 107
108/* control how magic key switches layers */
109//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true
110//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true
111//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false
112
113/* override magic key keymap */
114//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
115//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
116//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
117//#define MAGIC_KEY_HELP1 H
118//#define MAGIC_KEY_HELP2 SLASH
119//#define MAGIC_KEY_DEBUG D
120//#define MAGIC_KEY_DEBUG_MATRIX X
121//#define MAGIC_KEY_DEBUG_KBD K
122//#define MAGIC_KEY_DEBUG_MOUSE M
123//#define MAGIC_KEY_VERSION V
124//#define MAGIC_KEY_STATUS S
125//#define MAGIC_KEY_CONSOLE C
126//#define MAGIC_KEY_LAYER0_ALT1 ESC
127//#define MAGIC_KEY_LAYER0_ALT2 GRAVE
128//#define MAGIC_KEY_LAYER0 0
129//#define MAGIC_KEY_LAYER1 1
130//#define MAGIC_KEY_LAYER2 2
131//#define MAGIC_KEY_LAYER3 3
132//#define MAGIC_KEY_LAYER4 4
133//#define MAGIC_KEY_LAYER5 5
134//#define MAGIC_KEY_LAYER6 6
135//#define MAGIC_KEY_LAYER7 7
136//#define MAGIC_KEY_LAYER8 8
137//#define MAGIC_KEY_LAYER9 9
138//#define MAGIC_KEY_BOOTLOADER PAUSE
139//#define MAGIC_KEY_LOCK CAPS
140//#define MAGIC_KEY_EEPROM E
141//#define MAGIC_KEY_NKRO N
142//#define MAGIC_KEY_SLEEP_LED Z
143
63/* 144/*
64 * Feature disable options 145 * Feature disable options
65 * These options are also useful to firmware size reduction. 146 * These options are also useful to firmware size reduction.
diff --git a/quantum/template/keymaps/default/Makefile b/quantum/template/keymaps/default/Makefile
new file mode 100644
index 000000000..f4671a9d1
--- /dev/null
+++ b/quantum/template/keymaps/default/Makefile
@@ -0,0 +1,21 @@
1# Build Options
2# change to "no" to disable the options, or define them in the Makefile in
3# the appropriate keymap folder that will get included automatically
4#
5BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000)
6MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
7EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
8CONSOLE_ENABLE = no # Console for debug(+400)
9COMMAND_ENABLE = yes # Commands for debug and configuration
10NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
11BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
12MIDI_ENABLE = no # MIDI controls
13AUDIO_ENABLE = no # Audio output on port C6
14UNICODE_ENABLE = no # Unicode
15BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
16RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time.
17SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
18
19ifndef QUANTUM_DIR
20 include ../../../../Makefile
21endif \ No newline at end of file
diff --git a/quantum/template/keymaps/default/config.h b/quantum/template/keymaps/default/config.h
new file mode 100644
index 000000000..df06a2620
--- /dev/null
+++ b/quantum/template/keymaps/default/config.h
@@ -0,0 +1,8 @@
1#ifndef CONFIG_USER_H
2#define CONFIG_USER_H
3
4#include "../../config.h"
5
6// place overrides here
7
8#endif \ No newline at end of file
diff --git a/quantum/template/keymaps/default.c b/quantum/template/keymaps/default/keymap.c
index 4121fd860..e28a4723e 100644
--- a/quantum/template/keymaps/default.c
+++ b/quantum/template/keymaps/default/keymap.c
@@ -1,6 +1,3 @@
1// This is the canonical layout file for the Quantum project. If you want to add another keyboard,
2// this is the style you want to emulate.
3
4#include "%KEYBOARD%.h" 1#include "%KEYBOARD%.h"
5 2
6const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 3const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
@@ -28,3 +25,20 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
28 } 25 }
29 return MACRO_NONE; 26 return MACRO_NONE;
30}; 27};
28
29
30void matrix_init_user(void) {
31
32}
33
34void matrix_scan_user(void) {
35
36}
37
38bool process_record_user(uint16_t keycode, keyrecord_t *record) {
39 return true;
40}
41
42void led_set_user(uint8_t usb_led) {
43
44} \ No newline at end of file
diff --git a/quantum/template/keymaps/default/readme.md b/quantum/template/keymaps/default/readme.md
new file mode 100644
index 000000000..21aa663d5
--- /dev/null
+++ b/quantum/template/keymaps/default/readme.md
@@ -0,0 +1 @@
# The default keymap for %KEYBOARD% \ No newline at end of file
diff --git a/quantum/template/README.md b/quantum/template/readme.md
index dc163a2f4..b16f4cd76 100644
--- a/quantum/template/README.md
+++ b/quantum/template/readme.md
@@ -3,22 +3,26 @@
3 3
4## Quantum MK Firmware 4## Quantum MK Firmware
5 5
6For the full Quantum feature list, see [the parent README.md](/README.md). 6For the full Quantum feature list, see [the parent readme](/).
7 7
8## Building 8## Building
9 9
10Download or clone the whole firmware and navigate to the keyboard/%KEYBOARD% folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use the Teensy Loader to program your .hex file. 10Download or clone the whole firmware and navigate to the keyboards/%KEYBOARD% folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use the Teensy Loader to program your .hex file.
11 11
12Depending on which keymap you would like to use, you will have to compile slightly differently. 12Depending on which keymap you would like to use, you will have to compile slightly differently.
13 13
14### Default 14### Default
15To build with the default keymap, simply run `make`. 15
16To build with the default keymap, simply run `make default`.
16 17
17### Other Keymaps 18### Other Keymaps
18Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `<name>.c` and see keymap document (you can find in top README.md) and existent keymap files.
19 19
20To build the firmware binary hex file with a keymap just do `make` with `KEYMAP` option like: 20Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create a folder with the name of your keymap in the keymaps folder, and see keymap documentation (you can find in top readme.md) and existant keymap files.
21
22To build the firmware binary hex file with a keymap just do `make` with a keymap like this:
23
21``` 24```
22$ make KEYMAP=[default|jack|<name>] 25$ make [default|jack|<name>]
23``` 26```
24Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. \ No newline at end of file 27
28Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder.
diff --git a/quantum/template/rules.mk b/quantum/template/rules.mk
new file mode 100644
index 000000000..55898147d
--- /dev/null
+++ b/quantum/template/rules.mk
@@ -0,0 +1,67 @@
1# MCU name
2#MCU = at90usb1287
3MCU = atmega32u4
4
5# Processor frequency.
6# This will define a symbol, F_CPU, in all source code files equal to the
7# processor frequency in Hz. You can then use this symbol in your source code to
8# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
9# automatically to create a 32-bit value in your source code.
10#
11# This will be an integer division of F_USB below, as it is sourced by
12# F_USB after it has run through any CPU prescalers. Note that this value
13# does not *change* the processor frequency - it should merely be updated to
14# reflect the processor speed set externally so that the code can use accurate
15# software delays.
16F_CPU = 16000000
17
18
19#
20# LUFA specific
21#
22# Target architecture (see library "Board Types" documentation).
23ARCH = AVR8
24
25# Input clock frequency.
26# This will define a symbol, F_USB, in all source code files equal to the
27# input clock frequency (before any prescaling is performed) in Hz. This value may
28# differ from F_CPU if prescaling is used on the latter, and is required as the
29# raw input clock is fed directly to the PLL sections of the AVR for high speed
30# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
31# at the end, this will be done automatically to create a 32-bit value in your
32# source code.
33#
34# If no clock division is performed on the input clock inside the AVR (via the
35# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
36F_USB = $(F_CPU)
37
38# Interrupt driven control endpoint task(+60)
39OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
40
41
42# Boot Section Size in *bytes*
43# Teensy halfKay 512
44# Teensy++ halfKay 1024
45# Atmel DFU loader 4096
46# LUFA bootloader 4096
47# USBaspLoader 2048
48OPT_DEFS += -DBOOTLOADER_SIZE=512
49
50
51# Build Options
52# change yes to no to disable
53#
54BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000)
55MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700)
56EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450)
57CONSOLE_ENABLE ?= yes # Console for debug(+400)
58COMMAND_ENABLE ?= yes # Commands for debug and configuration
59# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
60SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend
61# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
62NKRO_ENABLE ?= no # USB Nkey Rollover
63BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default
64MIDI_ENABLE ?= no # MIDI controls
65UNICODE_ENABLE ?= no # Unicode
66BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID
67AUDIO_ENABLE ?= no # Audio output on port C6
diff --git a/quantum/template/template.c b/quantum/template/template.c
index 7be7dfc3d..5ef349583 100644
--- a/quantum/template/template.c
+++ b/quantum/template/template.c
@@ -1,29 +1,28 @@
1#include "%KEYBOARD%.h" 1#include "%KEYBOARD%.h"
2 2
3__attribute__ ((weak)) 3void matrix_init_kb(void) {
4void * matrix_init_user(void) {
5 // leave these blank
6};
7
8__attribute__ ((weak))
9void * matrix_scan_user(void) {
10 // leave these blank
11};
12
13void * matrix_init_kb(void) {
14 // put your keyboard start-up code here 4 // put your keyboard start-up code here
15 // runs once when the firmware starts up 5 // runs once when the firmware starts up
16 6
17 if (matrix_init_user) { 7 matrix_init_user();
18 (*matrix_init_user)(); 8}
19 }
20};
21 9
22void * matrix_scan_kb(void) { 10void matrix_scan_kb(void) {
23 // put your looping keyboard code here 11 // put your looping keyboard code here
24 // runs every cycle (a lot) 12 // runs every cycle (a lot)
25 13
26 if (matrix_scan_user) { 14 matrix_scan_user();
27 (*matrix_scan_user)(); 15}
28 } 16
29}; \ No newline at end of file 17bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
18 // put your per-action keyboard code here
19 // runs for every action, just before processing by the firmware
20
21 return process_record_user(keycode, record);
22}
23
24void led_set_kb(uint8_t usb_led) {
25 // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
26
27 led_set_user(usb_led);
28}
diff --git a/quantum/template/template.h b/quantum/template/template.h
index d4d78e4c9..cd78a54e3 100644
--- a/quantum/template/template.h
+++ b/quantum/template/template.h
@@ -1,10 +1,7 @@
1#ifndef %KEYBOARD_UPPERCASE%_H 1#ifndef %KEYBOARD_UPPERCASE%_H
2#define %KEYBOARD_UPPERCASE%_H 2#define %KEYBOARD_UPPERCASE%_H
3 3
4#include "matrix.h" 4#include "quantum.h"
5#include "keymap_common.h"
6#include "backlight.h"
7#include <stddef.h>
8 5
9// This a shortcut to help you visually see your layout. 6// This a shortcut to help you visually see your layout.
10// The following is an example using the Planck MIT layout 7// The following is an example using the Planck MIT layout
@@ -12,14 +9,11 @@
12// The second converts the arguments into a two-dimensional array 9// The second converts the arguments into a two-dimensional array
13#define KEYMAP( \ 10#define KEYMAP( \
14 k00, k01, k02, \ 11 k00, k01, k02, \
15 k10, k11, \ 12 k10, k11 \
16) \ 13) \
17{ \ 14{ \
18 { k00, k01, k02 }, \ 15 { k00, k01, k02 }, \
19 { k10, KC_NO, k11 }, \ 16 { k10, KC_NO, k11 }, \
20} 17}
21 18
22void * matrix_init_user(void); 19#endif
23void * matrix_scan_user(void);
24
25#endif \ No newline at end of file
diff --git a/quantum/tools/eeprom_reset.hex b/quantum/tools/eeprom_reset.hex
new file mode 100644
index 000000000..a8a75389f
--- /dev/null
+++ b/quantum/tools/eeprom_reset.hex
@@ -0,0 +1,9 @@
1:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
2:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
3:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
4:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
5:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
6:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
7:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
8:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90
9:00000001FF
diff --git a/quantum/tools/readme.md b/quantum/tools/readme.md
new file mode 100644
index 000000000..5f355256d
--- /dev/null
+++ b/quantum/tools/readme.md
@@ -0,0 +1,6 @@
1`eeprom_reset.hex` is to reset the eeprom on the Atmega32u4, like this:
2
3 dfu-programmer atmega32u4 erase
4 dfu-programmer atmega32u4 flash --eeprom eeprom_reset.hex
5
6 You'll need to reflash afterwards, because DFU requires the flash to be erased before messing with the eeprom.
diff --git a/quantum/variable_trace.c b/quantum/variable_trace.c
new file mode 100644
index 000000000..de580244c
--- /dev/null
+++ b/quantum/variable_trace.c
@@ -0,0 +1,110 @@
1#include "variable_trace.h"
2#include <stddef.h>
3#include <string.h>
4
5#ifdef NO_PRINT
6#error "You need undef NO_PRINT to use the variable trace feature"
7#endif
8
9#ifndef CONSOLE_ENABLE
10#error "The console needs to be enabled in the makefile to use the variable trace feature"
11#endif
12
13
14#define NUM_TRACED_VARIABLES 1
15#ifndef MAX_VARIABLE_TRACE_SIZE
16 #define MAX_VARIABLE_TRACE_SIZE 4
17#endif
18
19typedef struct {
20 const char* name;
21 void* addr;
22 unsigned size;
23 const char* func;
24 int line;
25 uint8_t last_value[MAX_VARIABLE_TRACE_SIZE];
26
27} traced_variable_t;
28
29static traced_variable_t traced_variables[NUM_TRACED_VARIABLES];
30
31void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line) {
32 verify_traced_variables(func, line);
33 if (size > MAX_VARIABLE_TRACE_SIZE) {
34#if defined(__AVR__)
35 xprintf("Traced variable \"%S\" exceeds the maximum size %d\n", name, size);
36#else
37 xprintf("Traced variable \"%s\" exceeds the maximum size %d\n", name, size);
38#endif
39 size = MAX_VARIABLE_TRACE_SIZE;
40 }
41 int index = -1;
42 for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
43 if (index == -1 && traced_variables[i].addr == NULL){
44 index = i;
45 }
46 else if (strcmp_P(name, traced_variables[i].name)==0) {
47 index = i;
48 break;
49 }
50 }
51
52 if (index == -1) {
53 xprintf("You can only trace %d variables at the same time\n", NUM_TRACED_VARIABLES);
54 return;
55 }
56
57 traced_variable_t* t = &traced_variables[index];
58 t->name = name;
59 t->addr = addr;
60 t->size = size;
61 t->func = func;
62 t->line = line;
63 memcpy(&t->last_value[0], addr, size);
64
65}
66
67void remove_traced_variable(const char* name, const char* func, int line) {
68 verify_traced_variables(func, line);
69 for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
70 if (strcmp_P(name, traced_variables[i].name)==0) {
71 traced_variables[i].name = 0;
72 traced_variables[i].addr = NULL;
73 break;
74 }
75 }
76}
77
78void verify_traced_variables(const char* func, int line) {
79 for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
80 traced_variable_t* t = &traced_variables[i];
81 if (t->addr != NULL && t->name != NULL) {
82 if (memcmp(t->last_value, t->addr, t->size)!=0){
83#if defined(__AVR__)
84 xprintf("Traced variable \"%S\" has been modified\n", t->name);
85 xprintf("Between %S:%d\n", t->func, t->line);
86 xprintf("And %S:%d\n", func, line);
87
88#else
89 xprintf("Traced variable \"%s\" has been modified\n", t->name);
90 xprintf("Between %s:%d\n", t->func, t->line);
91 xprintf("And %s:%d\n", func, line);
92#endif
93 xprintf("Previous value ");
94 for (int j=0; j<t->size;j++) {
95 print_hex8(t->last_value[j]);
96 }
97 xprintf("\nNew value ");
98 uint8_t* addr = (uint8_t*)(t->addr);
99 for (int j=0; j<t->size;j++) {
100 print_hex8(addr[j]);
101 }
102 xprintf("\n");
103 memcpy(t->last_value, addr, t->size);
104 }
105 }
106
107 t->func = func;
108 t->line = line;
109 }
110}
diff --git a/quantum/variable_trace.h b/quantum/variable_trace.h
new file mode 100644
index 000000000..46bd82786
--- /dev/null
+++ b/quantum/variable_trace.h
@@ -0,0 +1,34 @@
1#ifndef VARIABLE_TRACE_H
2#define VARIABLE_TRACE_H
3
4// For more information about the variable tracing see the readme.
5
6#include "print.h"
7
8#ifdef NUM_TRACED_VARIABLES
9
10// Start tracing a variable at the memory address addr
11// The name can be anything and is used only for reporting
12// The size should usually be the same size as the variable you are interested in
13#define ADD_TRACED_VARIABLE(name, addr, size) \
14 add_traced_variable(PSTR(name), (void*)addr, size, PSTR(__FILE__), __LINE__)
15
16// Stop tracing the variable with the given name
17#define REMOVE_TRACED_VARIABLE(name) remove_traced_variable(PSTR(name), PSTR(__FILE__), __LINE__)
18
19// Call to get messages when the variable has been changed
20#define VERIFY_TRACED_VARIABLES() verify_traced_variables(PSTR(__FILE__), __LINE__)
21
22#else
23
24#define ADD_TRACED_VARIABLE(name, addr, size)
25#define REMOVE_TRACED_VARIABLE(name)
26#define VERIFY_TRACED_VARIABLES()
27
28#endif
29
30// Don't call directly, use the macros instead
31void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line);
32void remove_traced_variable(const char* name, const char* func, int line);
33void verify_traced_variables(const char* func, int line);
34#endif
diff --git a/quantum/visualizer/LICENSE.md b/quantum/visualizer/LICENSE.md
new file mode 100644
index 000000000..22d4c3f08
--- /dev/null
+++ b/quantum/visualizer/LICENSE.md
@@ -0,0 +1,29 @@
1The files in this project are licensed under the MIT license
2It uses the following libraries
3uGFX - with it's own license, see the license.html file in the uGFX subfolder for more information
4tmk_core - is indirectly used and not included in the repository. It's licensed under the GPLv2 license
5Chibios - which is used by tmk_core is licensed under GPLv3.
6
7Therefore the effective license for any project using the library is GPLv3
8
9The MIT License (MIT)
10
11Copyright (c) 2016 Fred Sundvik
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in all
21copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29SOFTWARE.
diff --git a/quantum/visualizer/example_integration/callbacks.c b/quantum/visualizer/example_integration/callbacks.c
new file mode 100644
index 000000000..2539615d6
--- /dev/null
+++ b/quantum/visualizer/example_integration/callbacks.c
@@ -0,0 +1,36 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "keyboard.h"
26#include "action_layer.h"
27#include "visualizer.h"
28#include "host.h"
29
30void post_keyboard_init(void) {
31 visualizer_init();
32}
33
34void post_keyboard_task() {
35 visualizer_set_state(default_layer_state, layer_state, host_keyboard_leds());
36}
diff --git a/quantum/visualizer/example_integration/gfxconf.h b/quantum/visualizer/example_integration/gfxconf.h
new file mode 100644
index 000000000..304c5d187
--- /dev/null
+++ b/quantum/visualizer/example_integration/gfxconf.h
@@ -0,0 +1,325 @@
1/**
2 * This file has a different license to the rest of the uGFX system.
3 * You can copy, modify and distribute this file as you see fit.
4 * You do not need to publish your source modifications to this file.
5 * The only thing you are not permitted to do is to relicense it
6 * under a different license.
7 */
8
9/**
10 * Copy this file into your project directory and rename it as gfxconf.h
11 * Edit your copy to turn on the uGFX features you want to use.
12 * The values below are the defaults.
13 *
14 * Only remove the comments from lines where you want to change the
15 * default value. This allows definitions to be included from
16 * driver makefiles when required and provides the best future
17 * compatibility for your project.
18 *
19 * Please use spaces instead of tabs in this file.
20 */
21
22#ifndef _GFXCONF_H
23#define _GFXCONF_H
24
25
26///////////////////////////////////////////////////////////////////////////
27// GOS - One of these must be defined, preferably in your Makefile //
28///////////////////////////////////////////////////////////////////////////
29#define GFX_USE_OS_CHIBIOS TRUE
30//#define GFX_USE_OS_FREERTOS FALSE
31// #define GFX_FREERTOS_USE_TRACE FALSE
32//#define GFX_USE_OS_WIN32 FALSE
33//#define GFX_USE_OS_LINUX FALSE
34//#define GFX_USE_OS_OSX FALSE
35//#define GFX_USE_OS_ECOS FALSE
36//#define GFX_USE_OS_RAWRTOS FALSE
37//#define GFX_USE_OS_ARDUINO FALSE
38//#define GFX_USE_OS_KEIL FALSE
39//#define GFX_USE_OS_CMSIS FALSE
40//#define GFX_USE_OS_RAW32 FALSE
41// #define INTERRUPTS_OFF() optional_code
42// #define INTERRUPTS_ON() optional_code
43// These are not defined by default for some reason
44#define GOS_NEED_X_THREADS FALSE
45#define GOS_NEED_X_HEAP FALSE
46
47// Options that (should where relevant) apply to all operating systems
48 #define GFX_NO_INLINE FALSE
49// #define GFX_COMPILER GFX_COMPILER_UNKNOWN
50// #define GFX_CPU GFX_CPU_UNKNOWN
51// #define GFX_OS_HEAP_SIZE 0
52// #define GFX_OS_NO_INIT FALSE
53// #define GFX_OS_INIT_NO_WARNING FALSE
54// #define GFX_OS_PRE_INIT_FUNCTION myHardwareInitRoutine
55// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine
56// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine
57
58
59///////////////////////////////////////////////////////////////////////////
60// GDISP //
61///////////////////////////////////////////////////////////////////////////
62#define GFX_USE_GDISP TRUE
63
64//#define GDISP_NEED_AUTOFLUSH FALSE
65//#define GDISP_NEED_TIMERFLUSH FALSE
66//#define GDISP_NEED_VALIDATION TRUE
67//#define GDISP_NEED_CLIP TRUE
68//#define GDISP_NEED_CIRCLE FALSE
69//#define GDISP_NEED_ELLIPSE FALSE
70//#define GDISP_NEED_ARC FALSE
71//#define GDISP_NEED_ARCSECTORS FALSE
72//#define GDISP_NEED_CONVEX_POLYGON FALSE
73//#define GDISP_NEED_SCROLL FALSE
74//#define GDISP_NEED_PIXELREAD FALSE
75//#define GDISP_NEED_CONTROL FALSE
76//#define GDISP_NEED_QUERY FALSE
77//#define GDISP_NEED_MULTITHREAD FALSE
78//#define GDISP_NEED_STREAMING FALSE
79#define GDISP_NEED_TEXT TRUE
80// #define GDISP_NEED_TEXT_WORDWRAP FALSE
81// #define GDISP_NEED_ANTIALIAS FALSE
82// #define GDISP_NEED_UTF8 FALSE
83 #define GDISP_NEED_TEXT_KERNING TRUE
84// #define GDISP_INCLUDE_FONT_UI1 FALSE
85// #define GDISP_INCLUDE_FONT_UI2 FALSE // The smallest preferred font.
86// #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE
87// #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE
88// #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE
89// #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE
90// #define GDISP_INCLUDE_FONT_DEJAVUSANS20 FALSE
91// #define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE
92// #define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE
93 #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 TRUE
94// #define GDISP_INCLUDE_FONT_FIXED_10X20 FALSE
95// #define GDISP_INCLUDE_FONT_FIXED_7X14 FALSE
96 #define GDISP_INCLUDE_FONT_FIXED_5X8 TRUE
97// #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE
98// #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE
99// #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA FALSE
100// #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE
101// #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE
102// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE
103// #define GDISP_INCLUDE_USER_FONTS FALSE
104
105//#define GDISP_NEED_IMAGE FALSE
106// #define GDISP_NEED_IMAGE_NATIVE FALSE
107// #define GDISP_NEED_IMAGE_GIF FALSE
108// #define GDISP_NEED_IMAGE_BMP FALSE
109// #define GDISP_NEED_IMAGE_BMP_1 FALSE
110// #define GDISP_NEED_IMAGE_BMP_4 FALSE
111// #define GDISP_NEED_IMAGE_BMP_4_RLE FALSE
112// #define GDISP_NEED_IMAGE_BMP_8 FALSE
113// #define GDISP_NEED_IMAGE_BMP_8_RLE FALSE
114// #define GDISP_NEED_IMAGE_BMP_16 FALSE
115// #define GDISP_NEED_IMAGE_BMP_24 FALSE
116// #define GDISP_NEED_IMAGE_BMP_32 FALSE
117// #define GDISP_NEED_IMAGE_JPG FALSE
118// #define GDISP_NEED_IMAGE_PNG FALSE
119// #define GDISP_NEED_IMAGE_ACCOUNTING FALSE
120
121//#define GDISP_NEED_PIXMAP FALSE
122// #define GDISP_NEED_PIXMAP_IMAGE FALSE
123
124//#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE // If not defined the native hardware orientation is used.
125//#define GDISP_LINEBUF_SIZE 128
126//#define GDISP_STARTUP_COLOR Black
127#define GDISP_NEED_STARTUP_LOGO FALSE
128
129//#define GDISP_TOTAL_DISPLAYS 1
130
131//#define GDISP_DRIVER_LIST GDISPVMT_Win32, GDISPVMT_Win32
132// #ifdef GDISP_DRIVER_LIST
133// // For code and speed optimization define as TRUE or FALSE if all controllers have the same capability
134// #define GDISP_HARDWARE_STREAM_WRITE FALSE
135// #define GDISP_HARDWARE_STREAM_READ FALSE
136// #define GDISP_HARDWARE_STREAM_POS FALSE
137// #define GDISP_HARDWARE_DRAWPIXEL FALSE
138// #define GDISP_HARDWARE_CLEARS FALSE
139// #define GDISP_HARDWARE_FILLS FALSE
140// #define GDISP_HARDWARE_BITFILLS FALSE
141// #define GDISP_HARDWARE_SCROLL FALSE
142// #define GDISP_HARDWARE_PIXELREAD FALSE
143// #define GDISP_HARDWARE_CONTROL FALSE
144// #define GDISP_HARDWARE_QUERY FALSE
145// #define GDISP_HARDWARE_CLIP FALSE
146
147 #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888
148// #endif
149
150// The custom format is not defined for some reason, so define it as error
151// so we don't get compiler warnings
152#define GDISP_PIXELFORMAT_CUSTOM GDISP_PIXELFORMAT_ERROR
153
154#define GDISP_USE_GFXNET FALSE
155// #define GDISP_GFXNET_PORT 13001
156// #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP FALSE
157// #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE
158// #define GDISP_GFXNET_UNSAFE_SOCKETS FALSE
159
160
161///////////////////////////////////////////////////////////////////////////
162// GWIN //
163///////////////////////////////////////////////////////////////////////////
164#define GFX_USE_GWIN FALSE
165
166//#define GWIN_NEED_WINDOWMANAGER FALSE
167// #define GWIN_REDRAW_IMMEDIATE FALSE
168// #define GWIN_REDRAW_SINGLEOP FALSE
169// #define GWIN_NEED_FLASHING FALSE
170// #define GWIN_FLASHING_PERIOD 250
171
172//#define GWIN_NEED_CONSOLE FALSE
173// #define GWIN_CONSOLE_USE_HISTORY FALSE
174// #define GWIN_CONSOLE_HISTORY_AVERAGING FALSE
175// #define GWIN_CONSOLE_HISTORY_ATCREATE FALSE
176// #define GWIN_CONSOLE_ESCSEQ FALSE
177// #define GWIN_CONSOLE_USE_BASESTREAM FALSE
178// #define GWIN_CONSOLE_USE_FLOAT FALSE
179//#define GWIN_NEED_GRAPH FALSE
180//#define GWIN_NEED_GL3D FALSE
181
182//#define GWIN_NEED_WIDGET FALSE
183//#define GWIN_FOCUS_HIGHLIGHT_WIDTH 1
184// #define GWIN_NEED_LABEL FALSE
185// #define GWIN_LABEL_ATTRIBUTE FALSE
186// #define GWIN_NEED_BUTTON FALSE
187// #define GWIN_BUTTON_LAZY_RELEASE FALSE
188// #define GWIN_NEED_SLIDER FALSE
189// #define GWIN_SLIDER_NOSNAP FALSE
190// #define GWIN_SLIDER_DEAD_BAND 5
191// #define GWIN_SLIDER_TOGGLE_INC 20
192// #define GWIN_NEED_CHECKBOX FALSE
193// #define GWIN_NEED_IMAGE FALSE
194// #define GWIN_NEED_IMAGE_ANIMATION FALSE
195// #define GWIN_NEED_RADIO FALSE
196// #define GWIN_NEED_LIST FALSE
197// #define GWIN_NEED_LIST_IMAGES FALSE
198// #define GWIN_NEED_PROGRESSBAR FALSE
199// #define GWIN_PROGRESSBAR_AUTO FALSE
200// #define GWIN_NEED_KEYBOARD FALSE
201// #define GWIN_KEYBOARD_DEFAULT_LAYOUT VirtualKeyboard_English1
202// #define GWIN_NEED_KEYBOARD_ENGLISH1 TRUE
203// #define GWIN_NEED_TEXTEDIT FALSE
204// #define GWIN_FLAT_STYLING FALSE
205// #define GWIN_WIDGET_TAGS FALSE
206
207//#define GWIN_NEED_CONTAINERS FALSE
208// #define GWIN_NEED_CONTAINER FALSE
209// #define GWIN_NEED_FRAME FALSE
210// #define GWIN_NEED_TABSET FALSE
211// #define GWIN_TABSET_TABHEIGHT 18
212
213
214///////////////////////////////////////////////////////////////////////////
215// GEVENT //
216///////////////////////////////////////////////////////////////////////////
217#define GFX_USE_GEVENT FALSE
218
219//#define GEVENT_ASSERT_NO_RESOURCE FALSE
220//#define GEVENT_MAXIMUM_SIZE 32
221//#define GEVENT_MAX_SOURCE_LISTENERS 32
222
223
224///////////////////////////////////////////////////////////////////////////
225// GTIMER //
226///////////////////////////////////////////////////////////////////////////
227#define GFX_USE_GTIMER FALSE
228
229//#define GTIMER_THREAD_PRIORITY HIGH_PRIORITY
230//#define GTIMER_THREAD_WORKAREA_SIZE 2048
231
232
233///////////////////////////////////////////////////////////////////////////
234// GQUEUE //
235///////////////////////////////////////////////////////////////////////////
236#define GFX_USE_GQUEUE FALSE
237
238//#define GQUEUE_NEED_ASYNC FALSE
239//#define GQUEUE_NEED_GSYNC FALSE
240//#define GQUEUE_NEED_FSYNC FALSE
241//#define GQUEUE_NEED_BUFFERS FALSE
242
243///////////////////////////////////////////////////////////////////////////
244// GINPUT //
245///////////////////////////////////////////////////////////////////////////
246#define GFX_USE_GINPUT FALSE
247
248//#define GINPUT_NEED_MOUSE FALSE
249// #define GINPUT_TOUCH_STARTRAW FALSE
250// #define GINPUT_TOUCH_NOTOUCH FALSE
251// #define GINPUT_TOUCH_NOCALIBRATE FALSE
252// #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE
253// #define GINPUT_MOUSE_POLL_PERIOD 25
254// #define GINPUT_MOUSE_CLICK_TIME 300
255// #define GINPUT_TOUCH_CXTCLICK_TIME 700
256// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE
257// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE
258// #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32
259//#define GINPUT_NEED_KEYBOARD FALSE
260// #define GINPUT_KEYBOARD_POLL_PERIOD 200
261// #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32
262// #define GKEYBOARD_LAYOUT_OFF FALSE
263// #define GKEYBOARD_LAYOUT_SCANCODE2_US FALSE
264//#define GINPUT_NEED_TOGGLE FALSE
265//#define GINPUT_NEED_DIAL FALSE
266
267
268///////////////////////////////////////////////////////////////////////////
269// GFILE //
270///////////////////////////////////////////////////////////////////////////
271#define GFX_USE_GFILE FALSE
272
273//#define GFILE_NEED_PRINTG FALSE
274//#define GFILE_NEED_SCANG FALSE
275//#define GFILE_NEED_STRINGS FALSE
276//#define GFILE_NEED_FILELISTS FALSE
277//#define GFILE_NEED_STDIO FALSE
278//#define GFILE_NEED_NOAUTOMOUNT FALSE
279//#define GFILE_NEED_NOAUTOSYNC FALSE
280
281//#define GFILE_NEED_MEMFS FALSE
282//#define GFILE_NEED_ROMFS FALSE
283//#define GFILE_NEED_RAMFS FALSE
284//#define GFILE_NEED_FATFS FALSE
285//#define GFILE_NEED_NATIVEFS FALSE
286//#define GFILE_NEED_CHBIOSFS FALSE
287
288//#define GFILE_ALLOW_FLOATS FALSE
289//#define GFILE_ALLOW_DEVICESPECIFIC FALSE
290//#define GFILE_MAX_GFILES 3
291
292///////////////////////////////////////////////////////////////////////////
293// GADC //
294///////////////////////////////////////////////////////////////////////////
295#define GFX_USE_GADC FALSE
296
297//#define GADC_MAX_LOWSPEED_DEVICES 4
298
299
300///////////////////////////////////////////////////////////////////////////
301// GAUDIO //
302///////////////////////////////////////////////////////////////////////////
303#define GFX_USE_GAUDIO FALSE
304// There seems to be a bug in the ugfx code, the wrong define is used
305// So define it in order to avoid warnings
306#define GFX_USE_GAUDIN GFX_USE_GAUDIO
307// #define GAUDIO_NEED_PLAY FALSE
308// #define GAUDIO_NEED_RECORD FALSE
309
310
311///////////////////////////////////////////////////////////////////////////
312// GMISC //
313///////////////////////////////////////////////////////////////////////////
314#define GFX_USE_GMISC FALSE
315
316//#define GMISC_NEED_ARRAYOPS FALSE
317//#define GMISC_NEED_FASTTRIG FALSE
318//#define GMISC_NEED_FIXEDTRIG FALSE
319//#define GMISC_NEED_INVSQRT FALSE
320// #define GMISC_INVSQRT_MIXED_ENDIAN FALSE
321// #define GMISC_INVSQRT_REAL_SLOW FALSE
322//#define GMISC_NEED_MATRIXFLOAT2D FALSE
323//#define GMISC_NEED_MATRIXFIXED2D FALSE
324
325#endif /* _GFXCONF_H */
diff --git a/quantum/visualizer/example_integration/lcd_backlight_hal.c b/quantum/visualizer/example_integration/lcd_backlight_hal.c
new file mode 100644
index 000000000..913131b16
--- /dev/null
+++ b/quantum/visualizer/example_integration/lcd_backlight_hal.c
@@ -0,0 +1,91 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "lcd_backlight.h"
26#include "hal.h"
27
28#define RED_PIN 1
29#define GREEN_PIN 2
30#define BLUE_PIN 3
31#define CHANNEL_RED FTM0->CHANNEL[0]
32#define CHANNEL_GREEN FTM0->CHANNEL[1]
33#define CHANNEL_BLUE FTM0->CHANNEL[2]
34
35#define RGB_PORT PORTC
36#define RGB_PORT_GPIO GPIOC
37
38// Base FTM clock selection (72 MHz system clock)
39// @ 0xFFFF period, 72 MHz / (0xFFFF * 2) = Actual period
40// Higher pre-scalar will use the most power (also look the best)
41// Pre-scalar calculations
42// 0 - 72 MHz -> 549 Hz
43// 1 - 36 MHz -> 275 Hz
44// 2 - 18 MHz -> 137 Hz
45// 3 - 9 MHz -> 69 Hz (Slightly visible flicker)
46// 4 - 4 500 kHz -> 34 Hz (Visible flickering)
47// 5 - 2 250 kHz -> 17 Hz
48// 6 - 1 125 kHz -> 9 Hz
49// 7 - 562 500 Hz -> 4 Hz
50// Using a higher pre-scalar without flicker is possible but FTM0_MOD will need to be reduced
51// Which will reduce the brightness range
52#define PRESCALAR_DEFINE 0
53
54void lcd_backlight_hal_init(void) {
55 // Setup Backlight
56 SIM->SCGC6 |= SIM_SCGC6_FTM0;
57 FTM0->CNT = 0; // Reset counter
58
59 // PWM Period
60 // 16-bit maximum
61 FTM0->MOD = 0xFFFF;
62
63 // Set FTM to PWM output - Edge Aligned, Low-true pulses
64#define CNSC_MODE FTM_SC_CPWMS | FTM_SC_PS(4) | FTM_SC_CLKS(0)
65 CHANNEL_RED.CnSC = CNSC_MODE;
66 CHANNEL_GREEN.CnSC = CNSC_MODE;
67 CHANNEL_BLUE.CnSC = CNSC_MODE;
68
69 // System clock, /w prescalar setting
70 FTM0->SC = FTM_SC_CLKS(1) | FTM_SC_PS(PRESCALAR_DEFINE);
71
72 CHANNEL_RED.CnV = 0;
73 CHANNEL_GREEN.CnV = 0;
74 CHANNEL_BLUE.CnV = 0;
75
76 RGB_PORT_GPIO->PDDR |= (1 << RED_PIN);
77 RGB_PORT_GPIO->PDDR |= (1 << GREEN_PIN);
78 RGB_PORT_GPIO->PDDR |= (1 << BLUE_PIN);
79
80#define RGB_MODE PORTx_PCRn_SRE | PORTx_PCRn_DSE | PORTx_PCRn_MUX(4)
81 RGB_PORT->PCR[RED_PIN] = RGB_MODE;
82 RGB_PORT->PCR[GREEN_PIN] = RGB_MODE;
83 RGB_PORT->PCR[BLUE_PIN] = RGB_MODE;
84}
85
86void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b) {
87 CHANNEL_RED.CnV = r;
88 CHANNEL_GREEN.CnV = g;
89 CHANNEL_BLUE.CnV = b;
90}
91
diff --git a/quantum/visualizer/example_integration/visualizer_user.c b/quantum/visualizer/example_integration/visualizer_user.c
new file mode 100644
index 000000000..fc09fe2ea
--- /dev/null
+++ b/quantum/visualizer/example_integration/visualizer_user.c
@@ -0,0 +1,121 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25// Currently we are assuming that both the backlight and LCD are enabled
26// But it's entirely possible to write a custom visualizer that use only
27// one of them
28#ifndef LCD_BACKLIGHT_ENABLE
29#error This visualizer needs that LCD backlight is enabled
30#endif
31
32#ifndef LCD_ENABLE
33#error This visualizer needs that LCD is enabled
34#endif
35
36#include "visualizer.h"
37
38static const char* welcome_text[] = {"TMK", "Infinity Ergodox"};
39
40// Just an example how to write custom keyframe functions, we could have moved
41// all this into the init function
42bool display_welcome(keyframe_animation_t* animation, visualizer_state_t* state) {
43 (void)animation;
44 // Read the uGFX documentation for information how to use the displays
45 // http://wiki.ugfx.org/index.php/Main_Page
46 gdispClear(White);
47 // You can use static variables for things that can't be found in the animation
48 // or state structs
49 gdispDrawString(0, 3, welcome_text[0], state->font_dejavusansbold12, Black);
50 gdispDrawString(0, 15, welcome_text[1], state->font_dejavusansbold12, Black);
51 // Always remember to flush the display
52 gdispFlush();
53 // you could set the backlight color as well, but we won't do it here, since
54 // it's part of the following animation
55 // lcd_backlight_color(hue, saturation, intensity);
56 // We don't need constant updates, just drawing the screen once is enough
57 return false;
58}
59
60// Feel free to modify the animations below, or even add new ones if needed
61
62// Don't worry, if the startup animation is long, you can use the keyboard like normal
63// during that time
64static keyframe_animation_t startup_animation = {
65 .num_frames = 4,
66 .loop = false,
67 .frame_lengths = {0, MS2ST(1000), MS2ST(5000), 0},
68 .frame_functions = {display_welcome, keyframe_animate_backlight_color, keyframe_no_operation, enable_visualization},
69};
70
71// The color animation animates the LCD color when you change layers
72static keyframe_animation_t color_animation = {
73 .num_frames = 2,
74 .loop = false,
75 // Note that there's a 200 ms no-operation frame,
76 // this prevents the color from changing when activating the layer
77 // momentarily
78 .frame_lengths = {MS2ST(200), MS2ST(500)},
79 .frame_functions = {keyframe_no_operation, keyframe_animate_backlight_color},
80};
81
82// The LCD animation alternates between the layer name display and a
83// bitmap that displays all active layers
84static keyframe_animation_t lcd_animation = {
85 .num_frames = 2,
86 .loop = true,
87 .frame_lengths = {MS2ST(2000), MS2ST(2000)},
88 .frame_functions = {keyframe_display_layer_text, keyframe_display_layer_bitmap},
89};
90
91void initialize_user_visualizer(visualizer_state_t* state) {
92 // The brightness will be dynamically adjustable in the future
93 // But for now, change it here.
94 lcd_backlight_brightness(0x50);
95 state->current_lcd_color = LCD_COLOR(0x00, 0x00, 0xFF);
96 state->target_lcd_color = LCD_COLOR(0x10, 0xFF, 0xFF);
97 start_keyframe_animation(&startup_animation);
98}
99
100void update_user_visualizer_state(visualizer_state_t* state) {
101 // Add more tests, change the colors and layer texts here
102 // Usually you want to check the high bits (higher layers first)
103 // because that's the order layers are processed for keypresses
104 // You can for check for example:
105 // state->status.layer
106 // state->status.default_layer
107 // state->status.leds (see led.h for available statuses)
108 if (state->status.layer & 0x2) {
109 state->target_lcd_color = LCD_COLOR(0xA0, 0xB0, 0xFF);
110 state->layer_text = "Layer 2";
111 }
112 else {
113 state->target_lcd_color = LCD_COLOR(0x50, 0xB0, 0xFF);
114 state->layer_text = "Layer 1";
115 }
116 // You can also stop existing animations, and start your custom ones here
117 // remember that you should normally have only one animation for the LCD
118 // and one for the background. But you can also combine them if you want.
119 start_keyframe_animation(&lcd_animation);
120 start_keyframe_animation(&color_animation);
121}
diff --git a/quantum/visualizer/lcd_backlight.c b/quantum/visualizer/lcd_backlight.c
new file mode 100644
index 000000000..70187d1e0
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight.c
@@ -0,0 +1,85 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "lcd_backlight.h"
26#include <math.h>
27
28static uint8_t current_hue = 0x00;
29static uint8_t current_saturation = 0x00;
30static uint8_t current_intensity = 0xFF;
31static uint8_t current_brightness = 0x7F;
32
33void lcd_backlight_init(void) {
34 lcd_backlight_hal_init();
35 lcd_backlight_color(current_hue, current_saturation, current_intensity);
36}
37
38// This code is based on Brian Neltner's blogpost and example code
39// "Why every LED light should be using HSI colorspace".
40// http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi
41static void hsi_to_rgb(float h, float s, float i, uint16_t* r_out, uint16_t* g_out, uint16_t* b_out) {
42 unsigned int r, g, b;
43 h = fmodf(h, 360.0f); // cycle h around to 0-360 degrees
44 h = 3.14159f * h / 180.0f; // Convert to radians.
45 s = s > 0.0f ? (s < 1.0f ? s : 1.0f) : 0.0f; // clamp s and i to interval [0,1]
46 i = i > 0.0f ? (i < 1.0f ? i : 1.0f) : 0.0f;
47
48 // Math! Thanks in part to Kyle Miller.
49 if(h < 2.09439f) {
50 r = 65535.0f * i/3.0f *(1.0f + s * cos(h) / cosf(1.047196667f - h));
51 g = 65535.0f * i/3.0f *(1.0f + s *(1.0f - cosf(h) / cos(1.047196667f - h)));
52 b = 65535.0f * i/3.0f *(1.0f - s);
53 } else if(h < 4.188787) {
54 h = h - 2.09439;
55 g = 65535.0f * i/3.0f *(1.0f + s * cosf(h) / cosf(1.047196667f - h));
56 b = 65535.0f * i/3.0f *(1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
57 r = 65535.0f * i/3.0f *(1.0f - s);
58 } else {
59 h = h - 4.188787;
60 b = 65535.0f*i/3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h));
61 r = 65535.0f*i/3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
62 g = 65535.0f*i/3.0f * (1.0f - s);
63 }
64 *r_out = r > 65535 ? 65535 : r;
65 *g_out = g > 65535 ? 65535 : g;
66 *b_out = b > 65535 ? 65535 : b;
67}
68
69void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity) {
70 uint16_t r, g, b;
71 float hue_f = 360.0f * (float)hue / 255.0f;
72 float saturation_f = (float)saturation / 255.0f;
73 float intensity_f = (float)intensity / 255.0f;
74 intensity_f *= (float)current_brightness / 255.0f;
75 hsi_to_rgb(hue_f, saturation_f, intensity_f, &r, &g, &b);
76 current_hue = hue;
77 current_saturation = saturation;
78 current_intensity = intensity;
79 lcd_backlight_hal_color(r, g, b);
80}
81
82void lcd_backlight_brightness(uint8_t b) {
83 current_brightness = b;
84 lcd_backlight_color(current_hue, current_saturation, current_intensity);
85}
diff --git a/quantum/visualizer/lcd_backlight.h b/quantum/visualizer/lcd_backlight.h
new file mode 100644
index 000000000..dd3e37a06
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight.h
@@ -0,0 +1,42 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef LCD_BACKLIGHT_H_
26#define LCD_BACKLIGHT_H_
27#include "stdint.h"
28
29// Helper macros for storing hue, staturation and intensity as unsigned integers
30#define LCD_COLOR(hue, saturation, intensity) (hue << 16 | saturation << 8 | intensity)
31#define LCD_HUE(color) ((color >> 16) & 0xFF)
32#define LCD_SAT(color) ((color >> 8) & 0xFF)
33#define LCD_INT(color) (color & 0xFF)
34
35void lcd_backlight_init(void);
36void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity);
37void lcd_backlight_brightness(uint8_t b);
38
39void lcd_backlight_hal_init(void);
40void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b);
41
42#endif /* LCD_BACKLIGHT_H_ */
diff --git a/quantum/visualizer/led_test.c b/quantum/visualizer/led_test.c
new file mode 100644
index 000000000..a9abace8d
--- /dev/null
+++ b/quantum/visualizer/led_test.c
@@ -0,0 +1,170 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24#include "led_test.h"
25#include "gfx.h"
26#include "math.h"
27
28#define CROSSFADE_TIME 1000
29#define GRADIENT_TIME 3000
30
31keyframe_animation_t led_test_animation = {
32 .num_frames = 14,
33 .loop = true,
34 .frame_lengths = {
35 gfxMillisecondsToTicks(1000), // fade in
36 gfxMillisecondsToTicks(1000), // no op (leds on)
37 gfxMillisecondsToTicks(1000), // fade out
38 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
39 gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
40 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
41 gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
42 0, // mirror leds
43 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
44 gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
45 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
46 gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
47 0, // normal leds
48 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
49
50 },
51 .frame_functions = {
52 keyframe_fade_in_all_leds,
53 keyframe_no_operation,
54 keyframe_fade_out_all_leds,
55 keyframe_led_crossfade,
56 keyframe_led_left_to_right_gradient,
57 keyframe_led_crossfade,
58 keyframe_led_top_to_bottom_gradient,
59 keyframe_mirror_led_orientation,
60 keyframe_led_crossfade,
61 keyframe_led_left_to_right_gradient,
62 keyframe_led_crossfade,
63 keyframe_led_top_to_bottom_gradient,
64 keyframe_normal_led_orientation,
65 keyframe_led_crossfade,
66 },
67};
68
69static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
70 int frame_length = animation->frame_lengths[animation->current_frame];
71 int current_pos = frame_length - animation->time_left_in_frame;
72 int delta = to - from;
73 int luma = (delta * current_pos) / frame_length;
74 luma += from;
75 return luma;
76}
77
78static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint8_t from, uint8_t to) {
79 uint8_t luma = fade_led_color(animation, from, to);
80 color_t color = LUMA2COLOR(luma);
81 gdispGClear(LED_DISPLAY, color);
82}
83
84// TODO: Should be customizable per keyboard
85#define NUM_ROWS 7
86#define NUM_COLS 7
87
88static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS];
89static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS];
90
91static uint8_t compute_gradient_color(float t, float index, float num) {
92 const float two_pi = M_2_PI;
93 float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi;
94 float x = t * two_pi + normalized_index;
95 float v = 0.5 * (cosf(x) + 1.0f);
96 return (uint8_t)(255.0f * v);
97}
98
99bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) {
100 (void)state;
101 keyframe_fade_all_leds_from_to(animation, 0, 255);
102 return true;
103}
104
105bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) {
106 (void)state;
107 keyframe_fade_all_leds_from_to(animation, 255, 0);
108 return true;
109}
110
111bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
112 (void)state;
113 float frame_length = animation->frame_lengths[animation->current_frame];
114 float current_pos = frame_length - animation->time_left_in_frame;
115 float t = current_pos / frame_length;
116 for (int i=0; i< NUM_COLS; i++) {
117 uint8_t color = compute_gradient_color(t, i, NUM_COLS);
118 gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
119 }
120 return true;
121}
122
123bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
124 (void)state;
125 float frame_length = animation->frame_lengths[animation->current_frame];
126 float current_pos = frame_length - animation->time_left_in_frame;
127 float t = current_pos / frame_length;
128 for (int i=0; i< NUM_ROWS; i++) {
129 uint8_t color = compute_gradient_color(t, i, NUM_ROWS);
130 gdispGDrawLine(LED_DISPLAY, 0, i, NUM_COLS - 1, i, LUMA2COLOR(color));
131 }
132 return true;
133}
134
135static void copy_current_led_state(uint8_t* dest) {
136 for (int i=0;i<NUM_ROWS;i++) {
137 for (int j=0;j<NUM_COLS;j++) {
138 dest[i*NUM_COLS + j] = gdispGGetPixelColor(LED_DISPLAY, j, i);
139 }
140 }
141}
142bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
143 (void)state;
144 if (animation->first_update_of_frame) {
145 copy_current_led_state(&crossfade_start_frame[0][0]);
146 run_next_keyframe(animation, state);
147 copy_current_led_state(&crossfade_end_frame[0][0]);
148 }
149 for (int i=0;i<NUM_ROWS;i++) {
150 for (int j=0;j<NUM_COLS;j++) {
151 color_t color = LUMA2COLOR(fade_led_color(animation, crossfade_start_frame[i][j], crossfade_end_frame[i][j]));
152 gdispGDrawPixel(LED_DISPLAY, j, i, color);
153 }
154 }
155 return true;
156}
157
158bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
159 (void)state;
160 (void)animation;
161 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
162 return false;
163}
164
165bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
166 (void)state;
167 (void)animation;
168 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);
169 return false;
170}
diff --git a/quantum/visualizer/led_test.h b/quantum/visualizer/led_test.h
new file mode 100644
index 000000000..5e2325753
--- /dev/null
+++ b/quantum/visualizer/led_test.h
@@ -0,0 +1,41 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef TMK_VISUALIZER_LED_TEST_H_
26#define TMK_VISUALIZER_LED_TEST_H_
27
28#include "visualizer.h"
29
30bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state);
31bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state);
32bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
33bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
34bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
35bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
36bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
37
38extern keyframe_animation_t led_test_animation;
39
40
41#endif /* TMK_VISUALIZER_LED_TEST_H_ */
diff --git a/quantum/visualizer/readme.md b/quantum/visualizer/readme.md
new file mode 100644
index 000000000..545ba2270
--- /dev/null
+++ b/quantum/visualizer/readme.md
@@ -0,0 +1,18 @@
1# A visualization library for the TMK keyboard firmware
2
3This library is designed to work together with the [TMK keyboard firmware](https://github.com/tmk/tmk_keyboard). Currently it only works for [Chibios](http://www.chibios.org/)
4 flavors, but it would be possible to add support for other configurations as well. The LCD display functionality is provided by the [uGFX library](http://www.ugfx.org/).
5
6## To use this library as a user
7You can and should modify the visualizer\_user.c file. Check the comments in the file for more information.
8
9## To add this library to custom keyboard projects
10
111. Add tmk_visualizer as a submodule to your project
121. Set VISUALIZER_DIR in the main keyboard project makefile to point to the submodule
131. Define LCD\_ENABLE and/or LCD\_BACKLIGHT\_ENABLE, to enable support
141. Include the visualizer.mk make file
151. Copy the files in the example\_integration folder to your keyboard project
161. All other files than the callback.c file are included automatically, so you will need to add callback.c to your makefile manually. If you already have a similar file in your project, you can just copy the functions instead of the whole file.
171. Edit the files to match your hardware. You might might want to read the Chibios and UGfx documentation, for more information.
181. If you enable LCD support you might also have to write a custom uGFX display driver, check the uGFX documentation for that. You probably also want to enable SPI support in your Chibios configuration.
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
new file mode 100644
index 000000000..54f6faaa4
--- /dev/null
+++ b/quantum/visualizer/visualizer.c
@@ -0,0 +1,545 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "visualizer.h"
26#include "config.h"
27#include <string.h>
28#ifdef PROTOCOL_CHIBIOS
29#include "ch.h"
30#endif
31
32#include "gfx.h"
33
34#ifdef LCD_BACKLIGHT_ENABLE
35#include "lcd_backlight.h"
36#endif
37
38//#define DEBUG_VISUALIZER
39
40#ifdef DEBUG_VISUALIZER
41#include "debug.h"
42#else
43#include "nodebug.h"
44#endif
45
46#ifdef SERIAL_LINK_ENABLE
47#include "serial_link/protocol/transport.h"
48#include "serial_link/system/serial_link.h"
49#endif
50
51// Define this in config.h
52#ifndef VISUALIZER_THREAD_PRIORITY
53#define "Visualizer thread priority not defined"
54#endif
55
56
57static visualizer_keyboard_status_t current_status = {
58 .layer = 0xFFFFFFFF,
59 .default_layer = 0xFFFFFFFF,
60 .leds = 0xFFFFFFFF,
61 .suspended = false,
62};
63
64static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
65 return status1->layer == status2->layer &&
66 status1->default_layer == status2->default_layer &&
67 status1->leds == status2->leds &&
68 status1->suspended == status2->suspended;
69}
70
71static bool visualizer_enabled = false;
72
73#define MAX_SIMULTANEOUS_ANIMATIONS 4
74static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
75
76#ifdef SERIAL_LINK_ENABLE
77MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t);
78
79static remote_object_t* remote_objects[] = {
80 REMOTE_OBJECT(current_status),
81};
82
83#endif
84
85GDisplay* LCD_DISPLAY = 0;
86GDisplay* LED_DISPLAY = 0;
87
88__attribute__((weak))
89GDisplay* get_lcd_display(void) {
90 return gdispGetDisplay(0);
91}
92
93__attribute__((weak))
94GDisplay* get_led_display(void) {
95 return gdispGetDisplay(1);
96}
97
98void start_keyframe_animation(keyframe_animation_t* animation) {
99 animation->current_frame = -1;
100 animation->time_left_in_frame = 0;
101 animation->need_update = true;
102 int free_index = -1;
103 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
104 if (animations[i] == animation) {
105 return;
106 }
107 if (free_index == -1 && animations[i] == NULL) {
108 free_index=i;
109 }
110 }
111 if (free_index!=-1) {
112 animations[free_index] = animation;
113 }
114}
115
116void stop_keyframe_animation(keyframe_animation_t* animation) {
117 animation->current_frame = animation->num_frames;
118 animation->time_left_in_frame = 0;
119 animation->need_update = true;
120 animation->first_update_of_frame = false;
121 animation->last_update_of_frame = false;
122 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
123 if (animations[i] == animation) {
124 animations[i] = NULL;
125 return;
126 }
127 }
128}
129
130void stop_all_keyframe_animations(void) {
131 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
132 if (animations[i]) {
133 animations[i]->current_frame = animations[i]->num_frames;
134 animations[i]->time_left_in_frame = 0;
135 animations[i]->need_update = true;
136 animations[i]->first_update_of_frame = false;
137 animations[i]->last_update_of_frame = false;
138 animations[i] = NULL;
139 }
140 }
141}
142
143static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
144 // TODO: Clean up this messy code
145 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
146 animation->time_left_in_frame, delta);
147 if (animation->current_frame == animation->num_frames) {
148 animation->need_update = false;
149 return false;
150 }
151 if (animation->current_frame == -1) {
152 animation->current_frame = 0;
153 animation->time_left_in_frame = animation->frame_lengths[0];
154 animation->need_update = true;
155 animation->first_update_of_frame = true;
156 } else {
157 animation->time_left_in_frame -= delta;
158 while (animation->time_left_in_frame <= 0) {
159 int left = animation->time_left_in_frame;
160 if (animation->need_update) {
161 animation->time_left_in_frame = 0;
162 animation->last_update_of_frame = true;
163 (*animation->frame_functions[animation->current_frame])(animation, state);
164 animation->last_update_of_frame = false;
165 }
166 animation->current_frame++;
167 animation->need_update = true;
168 animation->first_update_of_frame = true;
169 if (animation->current_frame == animation->num_frames) {
170 if (animation->loop) {
171 animation->current_frame = 0;
172 }
173 else {
174 stop_keyframe_animation(animation);
175 return false;
176 }
177 }
178 delta = -left;
179 animation->time_left_in_frame = animation->frame_lengths[animation->current_frame];
180 animation->time_left_in_frame -= delta;
181 }
182 }
183 if (animation->need_update) {
184 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
185 animation->first_update_of_frame = false;
186 }
187
188 systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame;
189 if (wanted_sleep < *sleep_time) {
190 *sleep_time = wanted_sleep;
191 }
192
193 return true;
194}
195
196void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) {
197 int next_frame = animation->current_frame + 1;
198 if (next_frame == animation->num_frames) {
199 next_frame = 0;
200 }
201 keyframe_animation_t temp_animation = *animation;
202 temp_animation.current_frame = next_frame;
203 temp_animation.time_left_in_frame = animation->frame_lengths[next_frame];
204 temp_animation.first_update_of_frame = true;
205 temp_animation.last_update_of_frame = false;
206 temp_animation.need_update = false;
207 visualizer_state_t temp_state = *state;
208 (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
209}
210
211bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
212 (void)animation;
213 (void)state;
214 return false;
215}
216
217#ifdef LCD_BACKLIGHT_ENABLE
218bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
219 int frame_length = animation->frame_lengths[animation->current_frame];
220 int current_pos = frame_length - animation->time_left_in_frame;
221 uint8_t t_h = LCD_HUE(state->target_lcd_color);
222 uint8_t t_s = LCD_SAT(state->target_lcd_color);
223 uint8_t t_i = LCD_INT(state->target_lcd_color);
224 uint8_t p_h = LCD_HUE(state->prev_lcd_color);
225 uint8_t p_s = LCD_SAT(state->prev_lcd_color);
226 uint8_t p_i = LCD_INT(state->prev_lcd_color);
227
228 uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around
229 int d_h2 = t_h - p_h;
230 // Chose the shortest way around
231 int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1;
232 int d_s = t_s - p_s;
233 int d_i = t_i - p_i;
234
235 int hue = (d_h * current_pos) / frame_length;
236 int sat = (d_s * current_pos) / frame_length;
237 int intensity = (d_i * current_pos) / frame_length;
238 //dprintf("%X -> %X = %X\n", p_h, t_h, hue);
239 hue += p_h;
240 sat += p_s;
241 intensity += p_i;
242 state->current_lcd_color = LCD_COLOR(hue, sat, intensity);
243 lcd_backlight_color(
244 LCD_HUE(state->current_lcd_color),
245 LCD_SAT(state->current_lcd_color),
246 LCD_INT(state->current_lcd_color));
247
248 return true;
249}
250
251bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
252 (void)animation;
253 state->prev_lcd_color = state->target_lcd_color;
254 state->current_lcd_color = state->target_lcd_color;
255 lcd_backlight_color(
256 LCD_HUE(state->current_lcd_color),
257 LCD_SAT(state->current_lcd_color),
258 LCD_INT(state->current_lcd_color));
259 return false;
260}
261#endif // LCD_BACKLIGHT_ENABLE
262
263#ifdef LCD_ENABLE
264bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) {
265 (void)animation;
266 gdispClear(White);
267 gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black);
268 gdispFlush();
269 return false;
270}
271
272static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) {
273 for (int i=0; i<16;i++)
274 {
275 uint32_t mask = (1u << i);
276 if (default_layer & mask) {
277 if (layer & mask) {
278 *buffer = 'B';
279 } else {
280 *buffer = 'D';
281 }
282 } else if (layer & mask) {
283 *buffer = '1';
284 } else {
285 *buffer = '0';
286 }
287 ++buffer;
288
289 if (i==3 || i==7 || i==11) {
290 *buffer = ' ';
291 ++buffer;
292 }
293 }
294 *buffer = 0;
295}
296
297bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
298 (void)animation;
299 const char* layer_help = "1=On D=Default B=Both";
300 char layer_buffer[16 + 4]; // 3 spaces and one null terminator
301 gdispClear(White);
302 gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black);
303 format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer);
304 gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black);
305 format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer);
306 gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black);
307 gdispFlush();
308 return false;
309}
310#endif // LCD_ENABLE
311
312bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
313 (void)animation;
314 (void)state;
315#ifdef LCD_ENABLE
316 gdispSetPowerMode(powerOff);
317#endif
318#ifdef LCD_BACKLIGHT_ENABLE
319 lcd_backlight_hal_color(0, 0, 0);
320#endif
321 return false;
322}
323
324bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
325 (void)animation;
326 (void)state;
327#ifdef LCD_ENABLE
328 gdispSetPowerMode(powerOn);
329#endif
330 return false;
331}
332
333bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) {
334 (void)animation;
335 (void)state;
336 dprint("User visualizer inited\n");
337 visualizer_enabled = true;
338 return false;
339}
340
341// TODO: Optimize the stack size, this is probably way too big
342static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
343static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
344 (void)arg;
345
346 GListener event_listener;
347 geventListenerInit(&event_listener);
348 geventAttachSource(&event_listener, (GSourceHandle)&current_status, 0);
349
350 visualizer_keyboard_status_t initial_status = {
351 .default_layer = 0xFFFFFFFF,
352 .layer = 0xFFFFFFFF,
353 .leds = 0xFFFFFFFF,
354 .suspended = false,
355 };
356
357 visualizer_state_t state = {
358 .status = initial_status,
359 .current_lcd_color = 0,
360#ifdef LCD_ENABLE
361 .font_fixed5x8 = gdispOpenFont("fixed_5x8"),
362 .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12")
363#endif
364 };
365 initialize_user_visualizer(&state);
366 state.prev_lcd_color = state.current_lcd_color;
367
368#ifdef LCD_BACKLIGHT_ENABLE
369 lcd_backlight_color(
370 LCD_HUE(state.current_lcd_color),
371 LCD_SAT(state.current_lcd_color),
372 LCD_INT(state.current_lcd_color));
373#endif
374
375 systemticks_t sleep_time = TIME_INFINITE;
376 systemticks_t current_time = gfxSystemTicks();
377
378 while(true) {
379 systemticks_t new_time = gfxSystemTicks();
380 systemticks_t delta = new_time - current_time;
381 current_time = new_time;
382 bool enabled = visualizer_enabled;
383 if (!same_status(&state.status, &current_status)) {
384 if (visualizer_enabled) {
385 if (current_status.suspended) {
386 stop_all_keyframe_animations();
387 visualizer_enabled = false;
388 state.status = current_status;
389 user_visualizer_suspend(&state);
390 }
391 else {
392 state.status = current_status;
393 update_user_visualizer_state(&state);
394 }
395 state.prev_lcd_color = state.current_lcd_color;
396 }
397 }
398 if (!enabled && state.status.suspended && current_status.suspended == false) {
399 // Setting the status to the initial status will force an update
400 // when the visualizer is enabled again
401 state.status = initial_status;
402 state.status.suspended = false;
403 stop_all_keyframe_animations();
404 user_visualizer_resume(&state);
405 state.prev_lcd_color = state.current_lcd_color;
406 }
407 sleep_time = TIME_INFINITE;
408 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
409 if (animations[i]) {
410 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
411 }
412 }
413#ifdef LED_ENABLE
414 gdispGFlush(LED_DISPLAY);
415#endif
416
417#ifdef EMULATOR
418 draw_emulator();
419#endif
420 // The animation can enable the visualizer
421 // And we might need to update the state when that happens
422 // so don't sleep
423 if (enabled != visualizer_enabled) {
424 sleep_time = 0;
425 }
426
427 systemticks_t after_update = gfxSystemTicks();
428 unsigned update_delta = after_update - current_time;
429 if (sleep_time != TIME_INFINITE) {
430 if (sleep_time > update_delta) {
431 sleep_time -= update_delta;
432 }
433 else {
434 sleep_time = 0;
435 }
436 }
437 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
438#ifdef PROTOCOL_CHIBIOS
439 // The gEventWait function really takes milliseconds, even if the documentation says ticks.
440 // Unfortunately there's no generic ugfx conversion from system time to milliseconds,
441 // so let's do it in a platform dependent way.
442
443 // On windows the system ticks is the same as milliseconds anyway
444 if (sleep_time != TIME_INFINITE) {
445 sleep_time = ST2MS(sleep_time);
446 }
447#endif
448 geventEventWait(&event_listener, sleep_time);
449 }
450#ifdef LCD_ENABLE
451 gdispCloseFont(state.font_fixed5x8);
452 gdispCloseFont(state.font_dejavusansbold12);
453#endif
454
455 return 0;
456}
457
458void visualizer_init(void) {
459 gfxInit();
460
461#ifdef LCD_BACKLIGHT_ENABLE
462 lcd_backlight_init();
463#endif
464
465#ifdef SERIAL_LINK_ENABLE
466 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) );
467#endif
468
469#ifdef LCD_ENABLE
470 LCD_DISPLAY = get_lcd_display();
471#endif
472#ifdef LED_ENABLE
473 LED_DISPLAY = get_led_display();
474#endif
475
476 // We are using a low priority thread, the idea is to have it run only
477 // when the main thread is sleeping during the matrix scanning
478 gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack),
479 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
480}
481
482void update_status(bool changed) {
483 if (changed) {
484 GSourceListener* listener = geventGetSourceListener((GSourceHandle)&current_status, NULL);
485 if (listener) {
486 geventSendEvent(listener);
487 }
488 }
489#ifdef SERIAL_LINK_ENABLE
490 static systime_t last_update = 0;
491 systime_t current_update = chVTGetSystemTimeX();
492 systime_t delta = current_update - last_update;
493 if (changed || delta > MS2ST(10)) {
494 last_update = current_update;
495 visualizer_keyboard_status_t* r = begin_write_current_status();
496 *r = current_status;
497 end_write_current_status();
498 }
499#endif
500}
501
502void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
503 // Note that there's a small race condition here, the thread could read
504 // a state where one of these are set but not the other. But this should
505 // not really matter as it will be fixed during the next loop step.
506 // Alternatively a mutex could be used instead of the volatile variables
507
508 bool changed = false;
509#ifdef SERIAL_LINK_ENABLE
510 if (is_serial_link_connected ()) {
511 visualizer_keyboard_status_t* new_status = read_current_status();
512 if (new_status) {
513 if (!same_status(&current_status, new_status)) {
514 changed = true;
515 current_status = *new_status;
516 }
517 }
518 }
519 else {
520#else
521 {
522#endif
523 visualizer_keyboard_status_t new_status = {
524 .layer = state,
525 .default_layer = default_state,
526 .leds = leds,
527 .suspended = current_status.suspended,
528 };
529 if (!same_status(&current_status, &new_status)) {
530 changed = true;
531 current_status = new_status;
532 }
533 }
534 update_status(changed);
535}
536
537void visualizer_suspend(void) {
538 current_status.suspended = true;
539 update_status(true);
540}
541
542void visualizer_resume(void) {
543 current_status.suspended = false;
544 update_status(true);
545}
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
new file mode 100644
index 000000000..53e250725
--- /dev/null
+++ b/quantum/visualizer/visualizer.h
@@ -0,0 +1,147 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef VISUALIZER_H
26#define VISUALIZER_H
27#include <stdlib.h>
28#include <stdint.h>
29#include <stdbool.h>
30
31#include "gfx.h"
32
33#ifdef LCD_BACKLIGHT_ENABLE
34#include "lcd_backlight.h"
35#endif
36
37// This need to be called once at the start
38void visualizer_init(void);
39// This should be called at every matrix scan
40void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds);
41// This should be called when the keyboard goes to suspend state
42void visualizer_suspend(void);
43// This should be called when the keyboard wakes up from suspend state
44void visualizer_resume(void);
45
46// These functions are week, so they can be overridden by the keyboard
47// if needed
48GDisplay* get_lcd_display(void);
49GDisplay* get_led_display(void);
50
51// For emulator builds, this function need to be implemented
52#ifdef EMULATOR
53void draw_emulator(void);
54#endif
55
56// If you need support for more than 16 keyframes per animation, you can change this
57#define MAX_VISUALIZER_KEY_FRAMES 16
58
59struct keyframe_animation_t;
60
61typedef struct {
62 uint32_t layer;
63 uint32_t default_layer;
64 uint32_t leds; // See led.h for available statuses
65 bool suspended;
66} visualizer_keyboard_status_t;
67
68// The state struct is used by the various keyframe functions
69// It's also used for setting the LCD color and layer text
70// from the user customized code
71typedef struct visualizer_state_t {
72 // The user code should primarily be modifying these
73 uint32_t target_lcd_color;
74 const char* layer_text;
75
76 // The user visualizer(and animation functions) can read these
77 visualizer_keyboard_status_t status;
78
79 // These are used by the animation functions
80 uint32_t current_lcd_color;
81 uint32_t prev_lcd_color;
82#ifdef LCD_ENABLE
83 font_t font_fixed5x8;
84 font_t font_dejavusansbold12;
85#endif
86} visualizer_state_t;
87
88// Any custom keyframe function should have this signature
89// return true to get continuous updates, otherwise you will only get one
90// update per frame
91typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*);
92
93// Represents a keyframe animation, so fields are internal to the system
94// while others are meant to be initialized by the user code
95typedef struct keyframe_animation_t {
96 // These should be initialized
97 int num_frames;
98 bool loop;
99 int frame_lengths[MAX_VISUALIZER_KEY_FRAMES];
100 frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES];
101
102 // Used internally by the system, and can also be read by
103 // keyframe update functions
104 int current_frame;
105 int time_left_in_frame;
106 bool first_update_of_frame;
107 bool last_update_of_frame;
108 bool need_update;
109
110} keyframe_animation_t;
111
112extern GDisplay* LCD_DISPLAY;
113extern GDisplay* LED_DISPLAY;
114
115void start_keyframe_animation(keyframe_animation_t* animation);
116void stop_keyframe_animation(keyframe_animation_t* animation);
117// This runs the next keyframe, but does not update the animation state
118// Useful for crossfades for example
119void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state);
120
121// Some predefined keyframe functions that can be used by the user code
122// Does nothing, useful for adding delays
123bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state);
124// Animates the LCD backlight color between the current color and the target color (of the state)
125bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
126// Sets the backlight color to the target color
127bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
128// Displays the layer text centered vertically on the screen
129bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
130// Displays a bitmap (0/1) of all the currently active layers
131bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
132
133bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
134bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
135
136// Call this once, when the initial animation has finished, alternatively you can call it
137// directly from the initalize_user_visualizer function (the animation can be null)
138bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state);
139
140// These functions have to be implemented by the user
141void initialize_user_visualizer(visualizer_state_t* state);
142void update_user_visualizer_state(visualizer_state_t* state);
143void user_visualizer_suspend(visualizer_state_t* state);
144void user_visualizer_resume(visualizer_state_t* state);
145
146
147#endif /* VISUALIZER_H */
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
new file mode 100644
index 000000000..2f4a41d66
--- /dev/null
+++ b/quantum/visualizer/visualizer.mk
@@ -0,0 +1,61 @@
1# The MIT License (MIT)
2#
3# Copyright (c) 2016 Fred Sundvik
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23SRC += $(VISUALIZER_DIR)/visualizer.c
24EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR)
25GFXLIB = $(LIB_PATH)/ugfx
26VPATH += $(VISUALIZER_PATH)
27
28OPT_DEFS += -DVISUALIZER_ENABLE
29
30ifdef LCD_ENABLE
31OPT_DEFS += -DLCD_ENABLE
32ULIBS += -lm
33endif
34
35ifdef LCD_BACKLIGHT_ENABLE
36SRC += $(VISUALIZER_DIR)/lcd_backlight.c
37OPT_DEFS += -DLCD_BACKLIGHT_ENABLE
38endif
39
40ifdef LED_ENABLE
41SRC += $(VISUALIZER_DIR)/led_test.c
42OPT_DEFS += -DLED_ENABLE
43endif
44
45include $(GFXLIB)/gfx.mk
46SRC += $(patsubst $(TOP_DIR)/%,%,$(GFXSRC))
47OPT_DEFS += $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
48
49ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","")
50 SRC += keyboards/$(KEYBOARD)/keymaps/$(KEYMAP)/visualizer.c
51else
52 ifeq ("$(wildcard $(SUBPROJECT_PATH)/keymaps/$(KEYMAP)/visualizer.c)","")
53$(error "$(KEYMAP_PATH)/visualizer.c" does not exist)
54 else
55 SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/keymaps/$(KEYMAP)/visualizer.c
56 endif
57endif
58
59ifdef EMULATOR
60UINCDIR += $(TMK_DIR)/common
61endif \ No newline at end of file