aboutsummaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/analog.c53
-rw-r--r--quantum/analog.h36
-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.h117
-rw-r--r--quantum/audio/voices.c165
-rw-r--r--quantum/audio/voices.h31
-rw-r--r--quantum/audio/wave.h265
-rw-r--r--quantum/config_common.h119
-rw-r--r--quantum/keycode_config.c74
-rw-r--r--quantum/keycode_config.h21
-rw-r--r--quantum/keymap.h328
-rw-r--r--quantum/keymap_common.c171
-rw-r--r--quantum/keymap_extras/keymap_bepo.h311
-rw-r--r--quantum/keymap_extras/keymap_colemak.h75
-rw-r--r--quantum/keymap_extras/keymap_dvorak.h74
-rw-r--r--quantum/keymap_extras/keymap_fr_ch.h98
-rw-r--r--quantum/keymap_extras/keymap_french.h83
-rw-r--r--quantum/keymap_extras/keymap_french_osx.h77
-rw-r--r--quantum/keymap_extras/keymap_german.h99
-rw-r--r--quantum/keymap_extras/keymap_german_ch.h102
-rw-r--r--quantum/keymap_extras/keymap_german_osx.h97
-rw-r--r--quantum/keymap_extras/keymap_neo2.h63
-rw-r--r--quantum/keymap_extras/keymap_nordic.h59
-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_spanish.h62
-rw-r--r--quantum/keymap_extras/keymap_uk.h36
-rwxr-xr-xquantum/light_ws2812.c181
-rwxr-xr-xquantum/light_ws2812.h73
-rw-r--r--quantum/matrix.c297
-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.c66
-rw-r--r--quantum/process_keycode/process_midi.h207
-rw-r--r--quantum/process_keycode/process_music.c171
-rw-r--r--quantum/process_keycode/process_music.h27
-rw-r--r--quantum/process_keycode/process_tap_dance.c90
-rw-r--r--quantum/process_keycode/process_tap_dance.h62
-rw-r--r--quantum/process_keycode/process_unicode.c57
-rw-r--r--quantum/process_keycode/process_unicode.h122
-rw-r--r--quantum/quantum.c717
-rw-r--r--quantum/quantum.h107
-rw-r--r--quantum/rgblight.c505
-rw-r--r--quantum/rgblight.h86
-rw-r--r--quantum/serial_link/LICENSE21
-rw-r--r--quantum/serial_link/README.md1
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c145
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.h34
-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.c124
-rw-r--r--quantum/serial_link/protocol/transport.h151
-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.c506
-rw-r--r--quantum/serial_link/tests/frame_router_tests.c231
-rw-r--r--quantum/serial_link/tests/frame_validator_tests.c101
-rw-r--r--quantum/serial_link/tests/transport_tests.c168
-rw-r--r--quantum/serial_link/tests/triple_buffered_object_tests.c82
-rw-r--r--quantum/template/Makefile75
-rw-r--r--quantum/template/config.h162
-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.c44
-rw-r--r--quantum/template/keymaps/default/readme.md1
-rw-r--r--quantum/template/readme.md28
-rw-r--r--quantum/template/template.c28
-rw-r--r--quantum/template/template.h19
-rw-r--r--quantum/tools/eeprom_reset.hex9
-rw-r--r--quantum/tools/readme.md6
-rw-r--r--quantum/visualizer/.gitmodules3
-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/readme.md18
m---------quantum/visualizer/ugfx0
-rw-r--r--quantum/visualizer/visualizer.c481
-rw-r--r--quantum/visualizer/visualizer.h131
-rw-r--r--quantum/visualizer/visualizer.mk41
96 files changed, 11597 insertions, 0 deletions
diff --git a/quantum/analog.c b/quantum/analog.c
new file mode 100644
index 000000000..49b84ee0e
--- /dev/null
+++ b/quantum/analog.c
@@ -0,0 +1,53 @@
1// Simple analog to digitial conversion
2
3#include <avr/io.h>
4#include <avr/pgmspace.h>
5#include <stdint.h>
6#include "analog.h"
7
8
9static uint8_t aref = (1<<REFS0); // default to AREF = Vcc
10
11
12void analogReference(uint8_t mode)
13{
14 aref = mode & 0xC0;
15}
16
17
18// Arduino compatible pin input
19int16_t analogRead(uint8_t pin)
20{
21#if defined(__AVR_ATmega32U4__)
22 static const uint8_t PROGMEM pin_to_mux[] = {
23 0x00, 0x01, 0x04, 0x05, 0x06, 0x07,
24 0x25, 0x24, 0x23, 0x22, 0x21, 0x20};
25 if (pin >= 12) return 0;
26 return adc_read(pgm_read_byte(pin_to_mux + pin));
27#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
28 if (pin >= 8) return 0;
29 return adc_read(pin);
30#else
31 return 0;
32#endif
33}
34
35// Mux input
36int16_t adc_read(uint8_t mux)
37{
38#if defined(__AVR_AT90USB162__)
39 return 0;
40#else
41 uint8_t low;
42
43 ADCSRA = (1<<ADEN) | ADC_PRESCALER; // enable ADC
44 ADCSRB = (1<<ADHSM) | (mux & 0x20); // high speed mode
45 ADMUX = aref | (mux & 0x1F); // configure mux input
46 ADCSRA = (1<<ADEN) | ADC_PRESCALER | (1<<ADSC); // start the conversion
47 while (ADCSRA & (1<<ADSC)) ; // wait for result
48 low = ADCL; // must read LSB first
49 return (ADCH << 8) | low; // must read MSB only once!
50#endif
51}
52
53
diff --git a/quantum/analog.h b/quantum/analog.h
new file mode 100644
index 000000000..9b95a93be
--- /dev/null
+++ b/quantum/analog.h
@@ -0,0 +1,36 @@
1#ifndef _analog_h_included__
2#define _analog_h_included__
3
4#include <stdint.h>
5
6void analogReference(uint8_t mode);
7int16_t analogRead(uint8_t pin);
8int16_t adc_read(uint8_t mux);
9
10#define ADC_REF_POWER (1<<REFS0)
11#define ADC_REF_INTERNAL ((1<<REFS1) | (1<<REFS0))
12#define ADC_REF_EXTERNAL (0)
13
14// These prescaler values are for high speed mode, ADHSM = 1
15#if F_CPU == 16000000L
16#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS1))
17#elif F_CPU == 8000000L
18#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS0))
19#elif F_CPU == 4000000L
20#define ADC_PRESCALER ((1<<ADPS2))
21#elif F_CPU == 2000000L
22#define ADC_PRESCALER ((1<<ADPS1) | (1<<ADPS0))
23#elif F_CPU == 1000000L
24#define ADC_PRESCALER ((1<<ADPS1))
25#else
26#define ADC_PRESCALER ((1<<ADPS0))
27#endif
28
29// some avr-libc versions do not properly define ADHSM
30#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
31#if !defined(ADHSM)
32#define ADHSM (7)
33#endif
34#endif
35
36#endif
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..fc6fcdeef
--- /dev/null
+++ b/quantum/audio/song_list.h
@@ -0,0 +1,117 @@
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#define GOODBYE_SOUND \
32 E__NOTE(_E7), \
33 E__NOTE(_A6), \
34 ED_NOTE(_E6),
35
36#define STARTUP_SOUND \
37 ED_NOTE(_E7 ), \
38 E__NOTE(_CS7), \
39 E__NOTE(_E6 ), \
40 E__NOTE(_A6 ), \
41 M__NOTE(_CS7, 20),
42
43#define QWERTY_SOUND \
44 E__NOTE(_GS6 ), \
45 E__NOTE(_A6 ), \
46 S__NOTE(_REST), \
47 Q__NOTE(_E7 ),
48
49#define COLEMAK_SOUND \
50 E__NOTE(_GS6 ), \
51 E__NOTE(_A6 ), \
52 S__NOTE(_REST), \
53 ED_NOTE(_E7 ), \
54 S__NOTE(_REST), \
55 ED_NOTE(_GS7 ),
56
57#define DVORAK_SOUND \
58 E__NOTE(_GS6 ), \
59 E__NOTE(_A6 ), \
60 S__NOTE(_REST), \
61 E__NOTE(_E7 ), \
62 S__NOTE(_REST), \
63 E__NOTE(_FS7 ), \
64 S__NOTE(_REST), \
65 E__NOTE(_E7 ),
66
67#define PLOVER_SOUND \
68 E__NOTE(_GS6 ), \
69 E__NOTE(_A6 ), \
70 S__NOTE(_REST), \
71 ED_NOTE(_E7 ), \
72 S__NOTE(_REST), \
73 ED_NOTE(_A7 ),
74
75#define PLOVER_GOODBYE_SOUND \
76 E__NOTE(_GS6 ), \
77 E__NOTE(_A6 ), \
78 S__NOTE(_REST), \
79 ED_NOTE(_A7 ), \
80 S__NOTE(_REST), \
81 ED_NOTE(_E7 ),
82
83#define MUSIC_SCALE_SOUND \
84 E__NOTE(_A5 ), \
85 E__NOTE(_B5 ), \
86 E__NOTE(_CS6), \
87 E__NOTE(_D6 ), \
88 E__NOTE(_E6 ), \
89 E__NOTE(_FS6), \
90 E__NOTE(_GS6), \
91 E__NOTE(_A6 ),
92
93#define CAPS_LOCK_ON_SOUND \
94 E__NOTE(_A3), \
95 E__NOTE(_B3),
96
97#define CAPS_LOCK_OFF_SOUND \
98 E__NOTE(_B3), \
99 E__NOTE(_A3),
100
101#define SCROLL_LOCK_ON_SOUND \
102 E__NOTE(_D4), \
103 E__NOTE(_E4),
104
105#define SCROLL_LOCK_OFF_SOUND \
106 E__NOTE(_E4), \
107 E__NOTE(_D4),
108
109#define NUM_LOCK_ON_SOUND \
110 E__NOTE(_D5), \
111 E__NOTE(_E5),
112
113#define NUM_LOCK_OFF_SOUND \
114 E__NOTE(_E5), \
115 E__NOTE(_D5),
116
117#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/audio/wave.h b/quantum/audio/wave.h
new file mode 100644
index 000000000..6ebc34851
--- /dev/null
+++ b/quantum/audio/wave.h
@@ -0,0 +1,265 @@
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <avr/pgmspace.h>
4
5#define SINE_LENGTH 2048
6
7const uint8_t sinewave[] PROGMEM= //2048 values
8{
90x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82,
100x83,0x83,0x83,0x84,0x84,0x85,0x85,0x85,
110x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,
120x89,0x89,0x8a,0x8a,0x8a,0x8b,0x8b,0x8c,
130x8c,0x8c,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,
140x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92,
150x92,0x93,0x93,0x93,0x94,0x94,0x95,0x95,
160x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98,
170x98,0x99,0x99,0x9a,0x9a,0x9a,0x9b,0x9b,
180x9b,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e,
190x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1,
200xa2,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,
210xa5,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7,
220xa7,0xa8,0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,
230xaa,0xab,0xab,0xac,0xac,0xac,0xad,0xad,
240xad,0xae,0xae,0xae,0xaf,0xaf,0xb0,0xb0,
250xb0,0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb3,
260xb3,0xb4,0xb4,0xb4,0xb5,0xb5,0xb5,0xb6,
270xb6,0xb6,0xb7,0xb7,0xb7,0xb8,0xb8,0xb8,
280xb9,0xb9,0xba,0xba,0xba,0xbb,0xbb,0xbb,
290xbc,0xbc,0xbc,0xbd,0xbd,0xbd,0xbe,0xbe,
300xbe,0xbf,0xbf,0xbf,0xc0,0xc0,0xc0,0xc1,
310xc1,0xc1,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,
320xc4,0xc4,0xc4,0xc5,0xc5,0xc5,0xc6,0xc6,
330xc6,0xc7,0xc7,0xc7,0xc8,0xc8,0xc8,0xc9,
340xc9,0xc9,0xca,0xca,0xca,0xcb,0xcb,0xcb,
350xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce,
360xce,0xce,0xcf,0xcf,0xcf,0xcf,0xd0,0xd0,
370xd0,0xd1,0xd1,0xd1,0xd2,0xd2,0xd2,0xd2,
380xd3,0xd3,0xd3,0xd4,0xd4,0xd4,0xd5,0xd5,
390xd5,0xd5,0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,
400xd7,0xd8,0xd8,0xd8,0xd9,0xd9,0xd9,0xd9,
410xda,0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdc,
420xdc,0xdc,0xdc,0xdd,0xdd,0xdd,0xdd,0xde,
430xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xe0,
440xe0,0xe0,0xe1,0xe1,0xe1,0xe1,0xe2,0xe2,
450xe2,0xe2,0xe3,0xe3,0xe3,0xe3,0xe4,0xe4,
460xe4,0xe4,0xe4,0xe5,0xe5,0xe5,0xe5,0xe6,
470xe6,0xe6,0xe6,0xe7,0xe7,0xe7,0xe7,0xe8,
480xe8,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xe9,
490xea,0xea,0xea,0xea,0xea,0xeb,0xeb,0xeb,
500xeb,0xeb,0xec,0xec,0xec,0xec,0xec,0xed,
510xed,0xed,0xed,0xed,0xee,0xee,0xee,0xee,
520xee,0xef,0xef,0xef,0xef,0xef,0xf0,0xf0,
530xf0,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf1,
540xf1,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf3,
550xf3,0xf3,0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,
560xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,
570xf5,0xf5,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,
580xf6,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,
590xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,
600xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,
610xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,
620xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,
630xfb,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfc,
640xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,
650xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,
660xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfe,0xfe,
670xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
680xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
690xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,
700xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
710xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
720xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
730xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
740xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
750xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
760xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,
770xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
780xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,
790xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfd,0xfd,
800xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,
810xfd,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,
820xfc,0xfc,0xfc,0xfc,0xfc,0xfb,0xfb,0xfb,
830xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfa,
840xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,
850xfa,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,
860xf9,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,
870xf8,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,
880xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf5,
890xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf4,0xf4,
900xf4,0xf4,0xf4,0xf4,0xf3,0xf3,0xf3,0xf3,
910xf3,0xf3,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,
920xf1,0xf1,0xf1,0xf1,0xf1,0xf0,0xf0,0xf0,
930xf0,0xf0,0xf0,0xef,0xef,0xef,0xef,0xef,
940xee,0xee,0xee,0xee,0xee,0xed,0xed,0xed,
950xed,0xed,0xec,0xec,0xec,0xec,0xec,0xeb,
960xeb,0xeb,0xeb,0xeb,0xea,0xea,0xea,0xea,
970xea,0xe9,0xe9,0xe9,0xe9,0xe8,0xe8,0xe8,
980xe8,0xe8,0xe7,0xe7,0xe7,0xe7,0xe6,0xe6,
990xe6,0xe6,0xe5,0xe5,0xe5,0xe5,0xe4,0xe4,
1000xe4,0xe4,0xe4,0xe3,0xe3,0xe3,0xe3,0xe2,
1010xe2,0xe2,0xe2,0xe1,0xe1,0xe1,0xe1,0xe0,
1020xe0,0xe0,0xe0,0xdf,0xdf,0xdf,0xde,0xde,
1030xde,0xde,0xdd,0xdd,0xdd,0xdd,0xdc,0xdc,
1040xdc,0xdc,0xdb,0xdb,0xdb,0xda,0xda,0xda,
1050xda,0xd9,0xd9,0xd9,0xd9,0xd8,0xd8,0xd8,
1060xd7,0xd7,0xd7,0xd7,0xd6,0xd6,0xd6,0xd5,
1070xd5,0xd5,0xd5,0xd4,0xd4,0xd4,0xd3,0xd3,
1080xd3,0xd2,0xd2,0xd2,0xd2,0xd1,0xd1,0xd1,
1090xd0,0xd0,0xd0,0xcf,0xcf,0xcf,0xcf,0xce,
1100xce,0xce,0xcd,0xcd,0xcd,0xcc,0xcc,0xcc,
1110xcb,0xcb,0xcb,0xcb,0xca,0xca,0xca,0xc9,
1120xc9,0xc9,0xc8,0xc8,0xc8,0xc7,0xc7,0xc7,
1130xc6,0xc6,0xc6,0xc5,0xc5,0xc5,0xc4,0xc4,
1140xc4,0xc3,0xc3,0xc3,0xc2,0xc2,0xc2,0xc1,
1150xc1,0xc1,0xc0,0xc0,0xc0,0xbf,0xbf,0xbf,
1160xbe,0xbe,0xbe,0xbd,0xbd,0xbd,0xbc,0xbc,
1170xbc,0xbb,0xbb,0xbb,0xba,0xba,0xba,0xb9,
1180xb9,0xb8,0xb8,0xb8,0xb7,0xb7,0xb7,0xb6,
1190xb6,0xb6,0xb5,0xb5,0xb5,0xb4,0xb4,0xb4,
1200xb3,0xb3,0xb2,0xb2,0xb2,0xb1,0xb1,0xb1,
1210xb0,0xb0,0xb0,0xaf,0xaf,0xae,0xae,0xae,
1220xad,0xad,0xad,0xac,0xac,0xac,0xab,0xab,
1230xaa,0xaa,0xaa,0xa9,0xa9,0xa9,0xa8,0xa8,
1240xa7,0xa7,0xa7,0xa6,0xa6,0xa6,0xa5,0xa5,
1250xa5,0xa4,0xa4,0xa3,0xa3,0xa3,0xa2,0xa2,
1260xa2,0xa1,0xa1,0xa0,0xa0,0xa0,0x9f,0x9f,
1270x9e,0x9e,0x9e,0x9d,0x9d,0x9d,0x9c,0x9c,
1280x9b,0x9b,0x9b,0x9a,0x9a,0x9a,0x99,0x99,
1290x98,0x98,0x98,0x97,0x97,0x96,0x96,0x96,
1300x95,0x95,0x95,0x94,0x94,0x93,0x93,0x93,
1310x92,0x92,0x91,0x91,0x91,0x90,0x90,0x8f,
1320x8f,0x8f,0x8e,0x8e,0x8e,0x8d,0x8d,0x8c,
1330x8c,0x8c,0x8b,0x8b,0x8a,0x8a,0x8a,0x89,
1340x89,0x88,0x88,0x88,0x87,0x87,0x87,0x86,
1350x86,0x85,0x85,0x85,0x84,0x84,0x83,0x83,
1360x83,0x82,0x82,0x81,0x81,0x81,0x80,0x80,
1370x80,0x7f,0x7f,0x7e,0x7e,0x7e,0x7d,0x7d,
1380x7c,0x7c,0x7c,0x7b,0x7b,0x7a,0x7a,0x7a,
1390x79,0x79,0x78,0x78,0x78,0x77,0x77,0x77,
1400x76,0x76,0x75,0x75,0x75,0x74,0x74,0x73,
1410x73,0x73,0x72,0x72,0x71,0x71,0x71,0x70,
1420x70,0x70,0x6f,0x6f,0x6e,0x6e,0x6e,0x6d,
1430x6d,0x6c,0x6c,0x6c,0x6b,0x6b,0x6a,0x6a,
1440x6a,0x69,0x69,0x69,0x68,0x68,0x67,0x67,
1450x67,0x66,0x66,0x65,0x65,0x65,0x64,0x64,
1460x64,0x63,0x63,0x62,0x62,0x62,0x61,0x61,
1470x61,0x60,0x60,0x5f,0x5f,0x5f,0x5e,0x5e,
1480x5d,0x5d,0x5d,0x5c,0x5c,0x5c,0x5b,0x5b,
1490x5a,0x5a,0x5a,0x59,0x59,0x59,0x58,0x58,
1500x58,0x57,0x57,0x56,0x56,0x56,0x55,0x55,
1510x55,0x54,0x54,0x53,0x53,0x53,0x52,0x52,
1520x52,0x51,0x51,0x51,0x50,0x50,0x4f,0x4f,
1530x4f,0x4e,0x4e,0x4e,0x4d,0x4d,0x4d,0x4c,
1540x4c,0x4b,0x4b,0x4b,0x4a,0x4a,0x4a,0x49,
1550x49,0x49,0x48,0x48,0x48,0x47,0x47,0x47,
1560x46,0x46,0x45,0x45,0x45,0x44,0x44,0x44,
1570x43,0x43,0x43,0x42,0x42,0x42,0x41,0x41,
1580x41,0x40,0x40,0x40,0x3f,0x3f,0x3f,0x3e,
1590x3e,0x3e,0x3d,0x3d,0x3d,0x3c,0x3c,0x3c,
1600x3b,0x3b,0x3b,0x3a,0x3a,0x3a,0x39,0x39,
1610x39,0x38,0x38,0x38,0x37,0x37,0x37,0x36,
1620x36,0x36,0x35,0x35,0x35,0x34,0x34,0x34,
1630x34,0x33,0x33,0x33,0x32,0x32,0x32,0x31,
1640x31,0x31,0x30,0x30,0x30,0x30,0x2f,0x2f,
1650x2f,0x2e,0x2e,0x2e,0x2d,0x2d,0x2d,0x2d,
1660x2c,0x2c,0x2c,0x2b,0x2b,0x2b,0x2a,0x2a,
1670x2a,0x2a,0x29,0x29,0x29,0x28,0x28,0x28,
1680x28,0x27,0x27,0x27,0x26,0x26,0x26,0x26,
1690x25,0x25,0x25,0x25,0x24,0x24,0x24,0x23,
1700x23,0x23,0x23,0x22,0x22,0x22,0x22,0x21,
1710x21,0x21,0x21,0x20,0x20,0x20,0x1f,0x1f,
1720x1f,0x1f,0x1e,0x1e,0x1e,0x1e,0x1d,0x1d,
1730x1d,0x1d,0x1c,0x1c,0x1c,0x1c,0x1b,0x1b,
1740x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x19,
1750x19,0x19,0x19,0x18,0x18,0x18,0x18,0x17,
1760x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16,
1770x15,0x15,0x15,0x15,0x15,0x14,0x14,0x14,
1780x14,0x14,0x13,0x13,0x13,0x13,0x13,0x12,
1790x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11,
1800x11,0x10,0x10,0x10,0x10,0x10,0xf,0xf,
1810xf,0xf,0xf,0xf,0xe,0xe,0xe,0xe,
1820xe,0xd,0xd,0xd,0xd,0xd,0xd,0xc,
1830xc,0xc,0xc,0xc,0xc,0xb,0xb,0xb,
1840xb,0xb,0xb,0xa,0xa,0xa,0xa,0xa,
1850xa,0xa,0x9,0x9,0x9,0x9,0x9,0x9,
1860x9,0x8,0x8,0x8,0x8,0x8,0x8,0x8,
1870x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7,
1880x6,0x6,0x6,0x6,0x6,0x6,0x6,0x6,
1890x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,
1900x5,0x5,0x4,0x4,0x4,0x4,0x4,0x4,
1910x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3,
1920x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,
1930x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,
1940x2,0x2,0x2,0x2,0x2,0x2,0x1,0x1,
1950x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
1960x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
1970x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0,
1980x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
1990x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2000x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2010x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2020x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2030x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
2040x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,
2050x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
2060x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,
2070x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2,
2080x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,
2090x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3,
2100x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4,
2110x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5,
2120x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5,
2130x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6,
2140x6,0x7,0x7,0x7,0x7,0x7,0x7,0x7,
2150x7,0x8,0x8,0x8,0x8,0x8,0x8,0x8,
2160x9,0x9,0x9,0x9,0x9,0x9,0x9,0xa,
2170xa,0xa,0xa,0xa,0xa,0xa,0xb,0xb,
2180xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc,
2190xc,0xc,0xd,0xd,0xd,0xd,0xd,0xd,
2200xe,0xe,0xe,0xe,0xe,0xf,0xf,0xf,
2210xf,0xf,0xf,0x10,0x10,0x10,0x10,0x10,
2220x11,0x11,0x11,0x11,0x11,0x12,0x12,0x12,
2230x12,0x12,0x13,0x13,0x13,0x13,0x13,0x14,
2240x14,0x14,0x14,0x14,0x15,0x15,0x15,0x15,
2250x15,0x16,0x16,0x16,0x16,0x17,0x17,0x17,
2260x17,0x17,0x18,0x18,0x18,0x18,0x19,0x19,
2270x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1b,0x1b,
2280x1b,0x1b,0x1b,0x1c,0x1c,0x1c,0x1c,0x1d,
2290x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x1e,0x1f,
2300x1f,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21,
2310x21,0x21,0x22,0x22,0x22,0x22,0x23,0x23,
2320x23,0x23,0x24,0x24,0x24,0x25,0x25,0x25,
2330x25,0x26,0x26,0x26,0x26,0x27,0x27,0x27,
2340x28,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,
2350x2a,0x2a,0x2a,0x2b,0x2b,0x2b,0x2c,0x2c,
2360x2c,0x2d,0x2d,0x2d,0x2d,0x2e,0x2e,0x2e,
2370x2f,0x2f,0x2f,0x30,0x30,0x30,0x30,0x31,
2380x31,0x31,0x32,0x32,0x32,0x33,0x33,0x33,
2390x34,0x34,0x34,0x34,0x35,0x35,0x35,0x36,
2400x36,0x36,0x37,0x37,0x37,0x38,0x38,0x38,
2410x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,
2420x3b,0x3c,0x3c,0x3c,0x3d,0x3d,0x3d,0x3e,
2430x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,
2440x41,0x41,0x41,0x42,0x42,0x42,0x43,0x43,
2450x43,0x44,0x44,0x44,0x45,0x45,0x45,0x46,
2460x46,0x47,0x47,0x47,0x48,0x48,0x48,0x49,
2470x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b,
2480x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4e,
2490x4f,0x4f,0x4f,0x50,0x50,0x51,0x51,0x51,
2500x52,0x52,0x52,0x53,0x53,0x53,0x54,0x54,
2510x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57,
2520x58,0x58,0x58,0x59,0x59,0x59,0x5a,0x5a,
2530x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,
2540x5d,0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,
2550x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,
2560x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66,
2570x67,0x67,0x67,0x68,0x68,0x69,0x69,0x69,
2580x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c,
2590x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x70,
2600x70,0x70,0x71,0x71,0x71,0x72,0x72,0x73,
2610x73,0x73,0x74,0x74,0x75,0x75,0x75,0x76,
2620x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,
2630x79,0x7a,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c,
2640x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f
265}; \ No newline at end of file
diff --git a/quantum/config_common.h b/quantum/config_common.h
new file mode 100644
index 000000000..09a4fe701
--- /dev/null
+++ b/quantum/config_common.h
@@ -0,0 +1,119 @@
1#ifndef CONFIG_DEFINITIONS_H
2#define CONFIG_DEFINITIONS_H
3
4/* diode directions */
5#define COL2ROW 0
6#define ROW2COL 1
7/* I/O pins */
8#define B0 0x30
9#define B1 0x31
10#define B2 0x32
11#define B3 0x33
12#define B4 0x34
13#define B5 0x35
14#define B6 0x36
15#define B7 0x37
16#define C0 0x60
17#define C1 0x61
18#define C2 0x62
19#define C3 0x63
20#define C4 0x64
21#define C5 0x65
22#define C6 0x66
23#define C7 0x67
24#define D0 0x90
25#define D1 0x91
26#define D2 0x92
27#define D3 0x93
28#define D4 0x94
29#define D5 0x95
30#define D6 0x96
31#define D7 0x97
32#define E0 0xC0
33#define E1 0xC1
34#define E2 0xC2
35#define E3 0xC3
36#define E4 0xC4
37#define E5 0xC5
38#define E6 0xC6
39#define E7 0xC7
40#define F0 0xF0
41#define F1 0xF1
42#define F2 0xF2
43#define F3 0xF3
44#define F4 0xF4
45#define F5 0xF5
46#define F6 0xF6
47#define F7 0xF7
48
49/* USART configuration */
50#ifdef BLUETOOTH_ENABLE
51# ifdef __AVR_ATmega32U4__
52# define SERIAL_UART_BAUD 9600
53# define SERIAL_UART_DATA UDR1
54# define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1)
55# define SERIAL_UART_RXD_VECT USART1_RX_vect
56# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1))
57# define SERIAL_UART_INIT() do { \
58 /* baud rate */ \
59 UBRR1L = SERIAL_UART_UBRR; \
60 /* baud rate */ \
61 UBRR1H = SERIAL_UART_UBRR >> 8; \
62 /* enable TX */ \
63 UCSR1B = _BV(TXEN1); \
64 /* 8-bit data */ \
65 UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \
66 sei(); \
67 } while(0)
68# else
69# error "USART configuration is needed."
70#endif
71
72// I'm fairly sure these aren't needed, but oh well - Jack
73
74/*
75 * PS/2 Interrupt configuration
76 */
77#ifdef PS2_USE_INT
78/* uses INT1 for clock line(ATMega32U4) */
79#define PS2_CLOCK_PORT PORTD
80#define PS2_CLOCK_PIN PIND
81#define PS2_CLOCK_DDR DDRD
82#define PS2_CLOCK_BIT 1
83
84#define PS2_DATA_PORT PORTD
85#define PS2_DATA_PIN PIND
86#define PS2_DATA_DDR DDRD
87#define PS2_DATA_BIT 0
88
89#define PS2_INT_INIT() do { \
90 EICRA |= ((1<<ISC11) | \
91 (0<<ISC10)); \
92} while (0)
93#define PS2_INT_ON() do { \
94 EIMSK |= (1<<INT1); \
95} while (0)
96#define PS2_INT_OFF() do { \
97 EIMSK &= ~(1<<INT1); \
98} while (0)
99#define PS2_INT_VECT INT1_vect
100#endif
101
102/*
103 * PS/2 Busywait configuration
104 */
105#ifdef PS2_USE_BUSYWAIT
106#define PS2_CLOCK_PORT PORTD
107#define PS2_CLOCK_PIN PIND
108#define PS2_CLOCK_DDR DDRD
109#define PS2_CLOCK_BIT 1
110
111#define PS2_DATA_PORT PORTD
112#define PS2_DATA_PIN PIND
113#define PS2_DATA_DDR DDRD
114#define PS2_DATA_BIT 0
115#endif
116
117#endif
118
119#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..6216eefc9
--- /dev/null
+++ b/quantum/keycode_config.h
@@ -0,0 +1,21 @@
1#include "eeconfig.h"
2#include "keycode.h"
3
4uint16_t keycode_config(uint16_t keycode);
5
6/* NOTE: Not portable. Bit field order depends on implementation */
7typedef union {
8 uint16_t raw;
9 struct {
10 bool swap_control_capslock:1;
11 bool capslock_to_control:1;
12 bool swap_lalt_lgui:1;
13 bool swap_ralt_rgui:1;
14 bool no_gui:1;
15 bool swap_grave_esc:1;
16 bool swap_backslash_backspace:1;
17 bool nkro:1;
18 };
19} keymap_config_t;
20
21extern keymap_config_t keymap_config;
diff --git a/quantum/keymap.h b/quantum/keymap.h
new file mode 100644
index 000000000..73f99f821
--- /dev/null
+++ b/quantum/keymap.h
@@ -0,0 +1,328 @@
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 UNICODE_ENABLE
88 QK_UNICODE = 0x8000,
89 QK_UNICODE_MAX = 0xFFFF,
90#endif
91
92 // Loose keycodes - to be used directly
93
94 RESET = 0x7000,
95 DEBUG,
96 MAGIC_SWAP_CONTROL_CAPSLOCK,
97 MAGIC_CAPSLOCK_TO_CONTROL,
98 MAGIC_SWAP_LALT_LGUI,
99 MAGIC_SWAP_RALT_RGUI,
100 MAGIC_NO_GUI,
101 MAGIC_SWAP_GRAVE_ESC,
102 MAGIC_SWAP_BACKSLASH_BACKSPACE,
103 MAGIC_HOST_NKRO,
104 MAGIC_SWAP_ALT_GUI,
105 MAGIC_UNSWAP_CONTROL_CAPSLOCK,
106 MAGIC_UNCAPSLOCK_TO_CONTROL,
107 MAGIC_UNSWAP_LALT_LGUI,
108 MAGIC_UNSWAP_RALT_RGUI,
109 MAGIC_UNNO_GUI,
110 MAGIC_UNSWAP_GRAVE_ESC,
111 MAGIC_UNSWAP_BACKSLASH_BACKSPACE,
112 MAGIC_UNHOST_NKRO,
113 MAGIC_UNSWAP_ALT_GUI,
114
115 // Leader key
116#ifndef DISABLE_LEADER
117 KC_LEAD,
118#endif
119
120 // Audio on/off/toggle
121 AU_ON,
122 AU_OFF,
123 AU_TOG,
124
125 // Music mode on/off/toggle
126 MU_ON,
127 MU_OFF,
128 MU_TOG,
129
130 // Music voice iterate
131 MUV_IN,
132 MUV_DE,
133
134 // Midi mode on/off
135 MIDI_ON,
136 MIDI_OFF,
137
138 // Backlight functionality
139 BL_0,
140 BL_1,
141 BL_2,
142 BL_3,
143 BL_4,
144 BL_5,
145 BL_6,
146 BL_7,
147 BL_8,
148 BL_9,
149 BL_10,
150 BL_11,
151 BL_12,
152 BL_13,
153 BL_14,
154 BL_15,
155 BL_DEC,
156 BL_INC,
157 BL_TOGG,
158 BL_STEP,
159
160 // Left shift, open paren
161 KC_LSPO,
162
163 // Right shift, close paren
164 KC_RSPC,
165
166 // always leave at the end
167 SAFE_RANGE
168};
169
170// Ability to use mods in layouts
171#define LCTL(kc) (kc | QK_LCTL)
172#define LSFT(kc) (kc | QK_LSFT)
173#define LALT(kc) (kc | QK_LALT)
174#define LGUI(kc) (kc | QK_LGUI)
175#define RCTL(kc) (kc | QK_RCTL)
176#define RSFT(kc) (kc | QK_RSFT)
177#define RALT(kc) (kc | QK_RALT)
178#define RGUI(kc) (kc | QK_RGUI)
179
180#define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI)
181#define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT)
182#define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI)
183
184#define MOD_HYPR 0xf
185#define MOD_MEH 0x7
186
187
188// Aliases for shifted symbols
189// Each key has a 4-letter code, and some have longer aliases too.
190// While the long aliases are descriptive, the 4-letter codes
191// make for nicer grid layouts (everything lines up), and are
192// the preferred style for Quantum.
193#define KC_TILD LSFT(KC_GRV) // ~
194#define KC_TILDE KC_TILD
195
196#define KC_EXLM LSFT(KC_1) // !
197#define KC_EXCLAIM KC_EXLM
198
199#define KC_AT LSFT(KC_2) // @
200
201#define KC_HASH LSFT(KC_3) // #
202
203#define KC_DLR LSFT(KC_4) // $
204#define KC_DOLLAR KC_DLR
205
206#define KC_PERC LSFT(KC_5) // %
207#define KC_PERCENT KC_PERC
208
209#define KC_CIRC LSFT(KC_6) // ^
210#define KC_CIRCUMFLEX KC_CIRC
211
212#define KC_AMPR LSFT(KC_7) // &
213#define KC_AMPERSAND KC_AMPR
214
215#define KC_ASTR LSFT(KC_8) // *
216#define KC_ASTERISK KC_ASTR
217
218#define KC_LPRN LSFT(KC_9) // (
219#define KC_LEFT_PAREN KC_LPRN
220
221#define KC_RPRN LSFT(KC_0) // )
222#define KC_RIGHT_PAREN KC_RPRN
223
224#define KC_UNDS LSFT(KC_MINS) // _
225#define KC_UNDERSCORE KC_UNDS
226
227#define KC_PLUS LSFT(KC_EQL) // +
228
229#define KC_LCBR LSFT(KC_LBRC) // {
230#define KC_LEFT_CURLY_BRACE KC_LCBR
231
232#define KC_RCBR LSFT(KC_RBRC) // }
233#define KC_RIGHT_CURLY_BRACE KC_RCBR
234
235#define KC_LABK LSFT(KC_COMM) // <
236#define KC_LEFT_ANGLE_BRACKET KC_LABK
237
238#define KC_RABK LSFT(KC_DOT) // >
239#define KC_RIGHT_ANGLE_BRACKET KC_RABK
240
241#define KC_COLN LSFT(KC_SCLN) // :
242#define KC_COLON KC_COLN
243
244#define KC_PIPE LSFT(KC_BSLS) // |
245
246#define KC_LT LSFT(KC_COMM) // <
247
248#define KC_GT LSFT(KC_DOT) // >
249
250#define KC_QUES LSFT(KC_SLSH) // ?
251#define KC_QUESTION KC_QUES
252
253#define KC_DQT LSFT(KC_QUOT) // "
254#define KC_DOUBLE_QUOTE KC_DQT
255#define KC_DQUO KC_DQT
256
257#define KC_DELT KC_DELETE // Del key (four letter code)
258
259// Alias for function layers than expand past FN31
260#define FUNC(kc) (kc | QK_FUNCTION)
261
262// Aliases
263#define S(kc) LSFT(kc)
264#define F(kc) FUNC(kc)
265
266#define M(kc) (kc | QK_MACRO)
267
268#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)
269
270// L-ayer, T-ap - 256 keycode max, 16 layer max
271#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8))
272
273#define AG_SWAP MAGIC_SWAP_ALT_GUI
274#define AG_NORM MAGIC_UNSWAP_ALT_GUI
275
276#define BL_ON BL_9
277#define BL_OFF BL_0
278
279#define MI_ON MIDI_ON
280#define MI_OFF MIDI_OFF
281
282// GOTO layer - 16 layers max
283// when:
284// ON_PRESS = 1
285// ON_RELEASE = 2
286// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default.
287#define TO(layer, when) (layer | QK_TO | (when << 0x4))
288
289// Momentary switch layer - 256 layer max
290#define MO(layer) (layer | QK_MOMENTARY)
291
292// Set default layer - 256 layer max
293#define DF(layer) (layer | QK_DEF_LAYER)
294
295// Toggle to layer - 256 layer max
296#define TG(layer) (layer | QK_TOGGLE_LAYER)
297
298// One-shot layer - 256 layer max
299#define OSL(layer) (layer | QK_ONE_SHOT_LAYER)
300
301// One-shot mod
302#define OSM(layer) (layer | QK_ONE_SHOT_MOD)
303
304// M-od, T-ap - 256 keycode max
305#define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8))
306#define CTL_T(kc) MT(MOD_LCTL, kc)
307#define SFT_T(kc) MT(MOD_LSFT, kc)
308#define ALT_T(kc) MT(MOD_LALT, kc)
309#define GUI_T(kc) MT(MOD_LGUI, kc)
310#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal
311#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
312#define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui
313#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/
314
315// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap
316#define KC_HYPR HYPR(KC_NO)
317#define KC_MEH MEH(KC_NO)
318
319#ifdef UNICODE_ENABLE
320 // For sending unicode codes.
321 // You may not send codes over 7FFF -- this supports most of UTF8.
322 // To have a key that sends out Œ, go UC(0x0152)
323 #define UNICODE(n) (n | QK_UNICODE)
324 #define UC(n) UNICODE(n)
325#endif
326
327
328#endif
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c
new file mode 100644
index 000000000..76872ac59
--- /dev/null
+++ b/quantum/keymap_common.c
@@ -0,0 +1,171 @@
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#include "keymap.h"
19#include "report.h"
20#include "keycode.h"
21#include "action_layer.h"
22#if defined(__AVR__)
23#include <util/delay.h>
24#include <stdio.h>
25#endif
26#include "action.h"
27#include "action_macro.h"
28#include "debug.h"
29#include "backlight.h"
30#include "quantum.h"
31
32#ifdef MIDI_ENABLE
33 #include "keymap_midi.h"
34#endif
35
36extern keymap_config_t keymap_config;
37
38#include <inttypes.h>
39
40/* converts key to action */
41action_t action_for_key(uint8_t layer, keypos_t key)
42{
43 // 16bit keycodes - important
44 uint16_t keycode = keymap_key_to_keycode(layer, key);
45
46 // keycode remapping
47 keycode = keycode_config(keycode);
48
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;
53
54 switch (keycode) {
55 case KC_FN0 ... KC_FN31:
56 action.code = pgm_read_word(&actions[FN_INDEX(keycode)]);
57 break;
58 case KC_A ... KC_EXSEL:
59 case KC_LCTRL ... KC_RGUI:
60 action.code = ACTION_KEY(keycode);
61 break;
62 case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
63 action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
64 break;
65 case KC_AUDIO_MUTE ... KC_WWW_FAVORITES:
66 action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
67 break;
68 case KC_MS_UP ... KC_MS_ACCEL2:
69 action.code = ACTION_MOUSEKEY(keycode);
70 break;
71 case KC_TRNS:
72 action.code = ACTION_TRANSPARENT;
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
141 default:
142 action.code = ACTION_NO;
143 break;
144 }
145 return action;
146}
147
148__attribute__ ((weak))
149const uint16_t PROGMEM fn_actions[] = {
150
151};
152
153/* Macro */
154__attribute__ ((weak))
155const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
156{
157 return MACRO_NONE;
158}
159
160/* Function */
161__attribute__ ((weak))
162void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
163{
164}
165
166/* translates key to keycode */
167uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
168{
169 // Read entire word (16bits)
170 return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
171}
diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h
new file mode 100644
index 000000000..4c3096054
--- /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_QUOTE) // ?
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 AGR(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_colemak.h b/quantum/keymap_extras/keymap_colemak.h
new file mode 100644
index 000000000..b8d615748
--- /dev/null
+++ b/quantum/keymap_extras/keymap_colemak.h
@@ -0,0 +1,75 @@
1#ifndef KEYMAP_COLEMAK_H
2#define KEYMAP_COLEMAK_H
3
4#include "keymap.h"
5// For software implementation of colemak
6#define CM_Q KC_Q
7#define CM_W KC_W
8#define CM_F KC_E
9#define CM_P KC_R
10#define CM_G KC_T
11#define CM_J KC_Y
12#define CM_L KC_U
13#define CM_U KC_I
14#define CM_Y KC_O
15#define CM_SCLN KC_P
16
17#define CM_A KC_A
18#define CM_R KC_S
19#define CM_S KC_D
20#define CM_T KC_F
21#define CM_D KC_G
22#define CM_H KC_H
23#define CM_N KC_J
24#define CM_E KC_K
25#define CM_I KC_L
26#define CM_O KC_SCLN
27#define CM_COLN LSFT(CM_SCLN)
28
29#define CM_Z KC_Z
30#define CM_X KC_X
31#define CM_C KC_C
32#define CM_V KC_V
33#define CM_B KC_B
34#define CM_K KC_N
35#define CM_M KC_M
36#define CM_COMM KC_COMM
37#define CM_DOT KC_DOT
38#define CM_SLSH KC_SLSH
39
40// Make it easy to support these in macros
41// TODO: change macro implementation so these aren't needed
42#define KC_CM_Q CM_Q
43#define KC_CM_W CM_W
44#define KC_CM_F CM_F
45#define KC_CM_P CM_P
46#define KC_CM_G CM_G
47#define KC_CM_J CM_J
48#define KC_CM_L CM_L
49#define KC_CM_U CM_U
50#define KC_CM_Y CM_Y
51#define KC_CM_SCLN CM_SCLN
52
53#define KC_CM_A CM_A
54#define KC_CM_R CM_R
55#define KC_CM_S CM_S
56#define KC_CM_T CM_T
57#define KC_CM_D CM_D
58#define KC_CM_H CM_H
59#define KC_CM_N CM_N
60#define KC_CM_E CM_E
61#define KC_CM_I CM_I
62#define KC_CM_O CM_O
63
64#define KC_CM_Z CM_Z
65#define KC_CM_X CM_X
66#define KC_CM_C CM_C
67#define KC_CM_V CM_V
68#define KC_CM_B CM_B
69#define KC_CM_K CM_K
70#define KC_CM_M CM_M
71#define KC_CM_COMM CM_COMM
72#define KC_CM_DOT CM_DOT
73#define KC_CM_SLSH CM_SLSH
74
75#endif
diff --git a/quantum/keymap_extras/keymap_dvorak.h b/quantum/keymap_extras/keymap_dvorak.h
new file mode 100644
index 000000000..e855056e8
--- /dev/null
+++ b/quantum/keymap_extras/keymap_dvorak.h
@@ -0,0 +1,74 @@
1#ifndef KEYMAP_DVORAK_H
2#define KEYMAP_DVORAK_H
3
4#include "keymap.h"
5
6// Normal characters
7#define DV_GRV KC_GRV
8#define DV_1 KC_1
9#define DV_2 KC_2
10#define DV_3 KC_3
11#define DV_4 KC_4
12#define DV_5 KC_5
13#define DV_6 KC_6
14#define DV_7 KC_7
15#define DV_8 KC_8
16#define DV_9 KC_9
17#define DV_0 KC_0
18#define DV_LBRC KC_MINS
19#define DV_RBRC KC_EQL
20
21#define DV_QUOT KC_Q
22#define DV_COMM KC_W
23#define DV_DOT KC_E
24#define DV_P KC_R
25#define DV_Y KC_T
26#define DV_F KC_Y
27#define DV_G KC_U
28#define DV_C KC_I
29#define DV_R KC_O
30#define DV_L KC_P
31#define DV_SLSH KC_LBRC
32#define DV_EQL KC_RBRC
33
34#define DV_A KC_A
35#define DV_O KC_S
36#define DV_E KC_D
37#define DV_U KC_F
38#define DV_I KC_G
39#define DV_D KC_H
40#define DV_H KC_J
41#define DV_T KC_K
42#define DV_N KC_L
43#define DV_S KC_SCLN
44#define DV_MINS KC_QUOT
45
46#define DV_SCLN KC_Z
47#define DV_Q KC_X
48#define DV_J KC_C
49#define DV_K KC_V
50#define DV_X KC_B
51#define DV_B KC_N
52#define DV_M KC_M
53#define DV_W KC_COMM
54#define DV_V KC_DOT
55#define DV_Z KC_SLSH
56
57// Shifted characters
58#define DV_TILD LSFT(DV_GRV)
59#define DV_EXLM LSFT(DV_1)
60#define DV_AT LSFT(DV_2)
61#define DV_HASH LSFT(DV_3)
62#define DV_DLR LSFT(DV_4)
63#define DV_PERC LSFT(DV_5)
64#define DV_CIRC LSFT(DV_6)
65#define DV_AMPR LSFT(DV_7)
66#define DV_ASTR LSFT(DV_8)
67#define DV_LPRN LSFT(DV_9)
68#define DV_RPRN LSFT(DV_0)
69#define DV_LCBR LSFT(DV_LBRC)
70#define DV_RCBR LSFT(DV_RBRC)
71#define DV_UNDS LSFT(DV_MINS)
72#define DV_PLUS LSFT(DV_EQL)
73
74#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..3fd971357
--- /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) kc | 0x1400
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
new file mode 100644
index 000000000..2a44c80b1
--- /dev/null
+++ b/quantum/keymap_extras/keymap_french.h
@@ -0,0 +1,83 @@
1#ifndef KEYMAP_FRENCH_H
2#define KEYMAP_FRENCH_H
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) kc | 0x1400
8#define NO_ALGR KC_RALT
9
10// Normal characters
11#define FR_SUP2 KC_GRV
12#define FR_AMP KC_1
13#define FR_EACU KC_2
14#define FR_QUOT KC_3
15#define FR_APOS KC_4
16#define FR_LPRN KC_5
17#define FR_MINS KC_6
18#define FR_EGRV KC_7
19#define FR_UNDS KC_8
20#define FR_CCED KC_9
21#define FR_AGRV KC_0
22#define FR_RPRN KC_MINS
23#define FR_EQL KC_EQL
24
25#define FR_A KC_Q
26#define FR_Z KC_W
27#define FR_CIRC KC_LBRC
28#define FR_DLR KC_RBRC
29
30#define FR_Q KC_A
31#define FR_M KC_SCLN
32#define FR_UGRV KC_QUOT
33#define FR_ASTR KC_NUHS
34
35#define FR_LESS KC_NUBS
36#define FR_W KC_Z
37#define FR_COMM KC_M
38#define FR_SCLN KC_COMM
39#define FR_COLN KC_DOT
40#define FR_EXLM KC_SLSH
41
42// Shifted characters
43#define FR_1 LSFT(KC_1)
44#define FR_2 LSFT(KC_2)
45#define FR_3 LSFT(KC_3)
46#define FR_4 LSFT(KC_4)
47#define FR_5 LSFT(KC_5)
48#define FR_6 LSFT(KC_6)
49#define FR_7 LSFT(KC_7)
50#define FR_8 LSFT(KC_8)
51#define FR_9 LSFT(KC_9)
52#define FR_0 LSFT(KC_0)
53#define FR_OVRR LSFT(FR_RPRN)
54#define FR_PLUS LSFT(FR_EQL)
55
56#define FR_UMLT LSFT(FR_CIRC)
57#define FR_PND LSFT(FR_DLR)
58#define FR_PERC LSFT(FR_UGRV)
59#define FR_MU LSFT(FR_ASTR)
60
61#define FR_GRTR LSFT(FR_LESS)
62#define FR_QUES LSFT(FR_COMM)
63#define FR_DOT LSFT(FR_SCLN)
64#define FR_SLSH LSFT(FR_COLN)
65#define FR_SECT LSFT(FR_EXLM)
66
67// Alt Gr-ed characters
68#define FR_TILD ALGR(KC_2)
69#define FR_HASH ALGR(KC_3)
70#define FR_LCBR ALGR(KC_4)
71#define FR_LBRC ALGR(KC_5)
72#define FR_PIPE ALGR(KC_6)
73#define FR_GRV ALGR(KC_7)
74#define FR_BSLS ALGR(KC_8)
75#define FR_CIRC ALGR(KC_9)
76#define FR_AT ALGR(KC_0)
77#define FR_RBRC ALGR(FR_RPRN)
78#define FR_RCBR ALGR(FR_EQL)
79
80#define FR_EURO ALGR(KC_E)
81#define FR_BULT ALGR(FR_DLR)
82
83#endif \ No newline at end of file
diff --git a/quantum/keymap_extras/keymap_french_osx.h b/quantum/keymap_extras/keymap_french_osx.h
new file mode 100644
index 000000000..004d73ee2
--- /dev/null
+++ b/quantum/keymap_extras/keymap_french_osx.h
@@ -0,0 +1,77 @@
1#ifndef KEYMAP_FRENCH_OSX_H
2#define KEYMAP_FRENCH_OSX_H
3
4#include "keymap.h"
5
6// Normal characters
7#define FR_AT KC_GRV
8#define FR_AMP KC_1
9#define FR_EACU KC_2
10#define FR_QUOT KC_3
11#define FR_APOS KC_4
12#define FR_LPRN KC_5
13#define FR_SECT KC_6
14#define FR_EGRV KC_7
15#define FR_EXLM KC_8
16#define FR_CCED KC_9
17#define FR_AGRV KC_0
18#define FR_RPRN KC_MINS
19#define FR_MINS KC_EQL
20
21#define FR_A KC_Q
22#define FR_Z KC_W
23#define FR_CIRC KC_LBRC
24#define FR_DLR KC_RBRC
25
26#define FR_Q KC_A
27#define FR_M KC_SCLN
28#define FR_UGRV KC_QUOT
29#define FR_GRV KC_NUHS
30
31#define FR_LESS KC_NUBS
32#define FR_W KC_Z
33#define FR_COMM KC_M
34#define FR_SCLN KC_COMM
35#define FR_COLN KC_DOT
36#define FR_EQL KC_SLSH
37
38// Shifted characters
39#define FR_HASH LSFT(KC_GRV)
40#define FR_1 LSFT(KC_1)
41#define FR_2 LSFT(KC_2)
42#define FR_3 LSFT(KC_3)
43#define FR_4 LSFT(KC_4)
44#define FR_5 LSFT(KC_5)
45#define FR_6 LSFT(KC_6)
46#define FR_7 LSFT(KC_7)
47#define FR_8 LSFT(KC_8)
48#define FR_9 LSFT(KC_9)
49#define FR_0 LSFT(KC_0)
50#define FR_UNDS LSFT(FR_MINS)
51
52#define FR_UMLT LSFT(FR_CIRC)
53#define FR_ASTR LSFT(FR_DLR)
54
55#define FR_PERC LSFT(FR_UGRV)
56#define FR_PND LSFT(FR_GRV)
57
58#define FR_GRTR LSFT(FR_LESS)
59#define FR_QUES LSFT(FR_COMM)
60#define FR_DOT LSFT(FR_SCLN)
61#define FR_SLSH LSFT(FR_COLN)
62#define FR_PLUS LSFT(FR_EQL)
63
64// Alted characters
65#define FR_LCBR LALT(KC_5)
66#define FR_RCBR LALT(FR_RPRN)
67#define FR_EURO LALT(KC_E)
68#define FR_BULT LALT(FR_DLR)
69#define FR_TILD LALT(KC_N)
70
71// Shift+Alt-ed characters
72#define FR_LBRC LSFT(LALT(KC_5))
73#define FR_RBRC LSFT(LALT(FR_RPRN))
74#define FR_PIPE LSFT(LALT(KC_L))
75#define FR_BSLS LSFT(LALT(FR_COLN))
76
77#endif \ No newline at end of file
diff --git a/quantum/keymap_extras/keymap_german.h b/quantum/keymap_extras/keymap_german.h
new file mode 100644
index 000000000..3f9ae8bad
--- /dev/null
+++ b/quantum/keymap_extras/keymap_german.h
@@ -0,0 +1,99 @@
1#ifndef KEYMAP_GERMAN
2#define KEYMAP_GERMAN
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) kc | 0x1400
8#define DE_ALGR KC_RALT
9
10// normal characters
11#define DE_Z KC_Y
12#define DE_Y KC_Z
13
14#define DE_A KC_A
15#define DE_B KC_B
16#define DE_C KC_C
17#define DE_D KC_D
18#define DE_E KC_E
19#define DE_F KC_F
20#define DE_G KC_G
21#define DE_H KC_H
22#define DE_I KC_I
23#define DE_J KC_J
24#define DE_K KC_K
25#define DE_L KC_L
26#define DE_M KC_M
27#define DE_N KC_N
28#define DE_O KC_O
29#define DE_P KC_P
30#define DE_Q KC_Q
31#define DE_R KC_R
32#define DE_S KC_S
33#define DE_T KC_T
34#define DE_U KC_U
35#define DE_V KC_V
36#define DE_W KC_W
37#define DE_X KC_X
38
39#define DE_0 KC_0
40#define DE_1 KC_1
41#define DE_2 KC_2
42#define DE_3 KC_3
43#define DE_4 KC_4
44#define DE_5 KC_5
45#define DE_6 KC_6
46#define DE_7 KC_7
47#define DE_8 KC_8
48#define DE_9 KC_9
49
50#define DE_DOT KC_DOT
51#define DE_COMM KC_COMM
52
53#define DE_SS KC_MINS
54#define DE_AE KC_QUOT
55#define DE_UE KC_LBRC
56#define DE_OE KC_SCLN
57
58#define DE_CIRC KC_GRAVE // accent circumflex ^ and ring °
59#define DE_ACUT KC_EQL // accent acute ´ and grave `
60#define DE_PLUS KC_RBRC // + and * and ~
61#define DE_HASH KC_BSLS // # and '
62#define DE_LESS KC_NUBS // < and > and |
63#define DE_MINS KC_SLSH // - and _
64
65// shifted characters
66#define DE_RING LSFT(DE_CIRC) // °
67#define DE_EXLM LSFT(KC_1) // !
68#define DE_DQOT LSFT(KC_2) // "
69#define DE_PARA LSFT(KC_3) // §
70#define DE_DLR LSFT(KC_4) // $
71#define DE_PERC LSFT(KC_5) // %
72#define DE_AMPR LSFT(KC_6) // &
73#define DE_SLSH LSFT(KC_7) // /
74#define DE_LPRN LSFT(KC_8) // (
75#define DE_RPRN LSFT(KC_9) // )
76#define DE_EQL LSFT(KC_0) // =
77#define DE_QST LSFT(DE_SS) // ?
78#define DE_GRV LSFT(DE_ACUT) // `
79#define DE_ASTR LSFT(DE_PLUS) // *
80#define DE_QUOT LSFT(DE_HASH) // '
81#define DE_MORE LSFT(DE_LESS) // >
82#define DE_COLN LSFT(KC_DOT) // :
83#define DE_SCLN LSFT(KC_COMM) // ;
84#define DE_UNDS LSFT(DE_MINS) // _
85
86// Alt Gr-ed characters
87#define DE_SQ2 ALGR(KC_2) // ²
88#define DE_SQ3 ALGR(KC_3) // ³
89#define DE_LCBR ALGR(KC_7) // {
90#define DE_LBRC ALGR(KC_8) // [
91#define DE_RBRC ALGR(KC_9) // ]
92#define DE_RCBR ALGR(KC_0) // }
93#define DE_BSLS ALGR(DE_SS) // backslash
94#define DE_AT ALGR(KC_Q) // @
95#define DE_EURO ALGR(KC_E) // €
96#define DE_TILD ALGR(DE_PLUS) // ~
97#define DE_PIPE ALGR(DE_LESS) // |
98
99#endif
diff --git a/quantum/keymap_extras/keymap_german_ch.h b/quantum/keymap_extras/keymap_german_ch.h
new file mode 100644
index 000000000..6a782bcd7
--- /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) kc | 0x1400
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
new file mode 100644
index 000000000..f63f06618
--- /dev/null
+++ b/quantum/keymap_extras/keymap_german_osx.h
@@ -0,0 +1,97 @@
1#ifndef KEYMAP_GERMAN_OSX
2#define KEYMAP_GERMAN_OSX
3
4#include "keymap.h"
5
6// Alt gr
7
8// normal characters
9#define DE_OSX_Z KC_Y
10#define DE_OSX_Y KC_Z
11
12#define DE_OSX_A KC_A
13#define DE_OSX_B KC_B
14#define DE_OSX_C KC_C
15#define DE_OSX_D KC_D
16#define DE_OSX_E KC_E
17#define DE_OSX_F KC_F
18#define DE_OSX_G KC_G
19#define DE_OSX_H KC_H
20#define DE_OSX_I KC_I
21#define DE_OSX_J KC_J
22#define DE_OSX_K KC_K
23#define DE_OSX_L KC_L
24#define DE_OSX_M KC_M
25#define DE_OSX_N KC_N
26#define DE_OSX_O KC_O
27#define DE_OSX_P KC_P
28#define DE_OSX_Q KC_Q
29#define DE_OSX_R KC_R
30#define DE_OSX_S KC_S
31#define DE_OSX_T KC_T
32#define DE_OSX_U KC_U
33#define DE_OSX_V KC_V
34#define DE_OSX_W KC_W
35#define DE_OSX_X KC_X
36
37#define DE_OSX_0 KC_0
38#define DE_OSX_1 KC_1
39#define DE_OSX_2 KC_2
40#define DE_OSX_3 KC_3
41#define DE_OSX_4 KC_4
42#define DE_OSX_5 KC_5
43#define DE_OSX_6 KC_6
44#define DE_OSX_7 KC_7
45#define DE_OSX_8 KC_8
46#define DE_OSX_9 KC_9
47
48#define DE_OSX_DOT KC_DOT
49#define DE_OSX_COMM KC_COMM
50
51#define DE_OSX_SS KC_MINS
52#define DE_OSX_AE KC_QUOT
53#define DE_OSX_UE KC_LBRC
54#define DE_OSX_OE KC_SCLN
55
56#define DE_OSX_CIRC KC_NUBS // accent circumflex ^ and ring °
57#define DE_OSX_ACUT KC_EQL // accent acute ´ and grave `
58#define DE_OSX_PLUS KC_RBRC // + and * and ~
59#define DE_OSX_HASH KC_BSLS // # and '
60#define DE_OSX_LESS KC_GRV // < and > and |
61#define DE_OSX_MINS KC_SLSH // - and _
62
63// shifted characters
64#define DE_OSX_RING LSFT(DE_OSX_CIRC) // °
65#define DE_OSX_EXLM LSFT(KC_1) // !
66#define DE_OSX_DQOT LSFT(KC_2) // "
67#define DE_OSX_PARA LSFT(KC_3) // §
68#define DE_OSX_DLR LSFT(KC_4) // $
69#define DE_OSX_PERC LSFT(KC_5) // %
70#define DE_OSX_AMPR LSFT(KC_6) // &
71#define DE_OSX_SLSH LSFT(KC_7) // /
72#define DE_OSX_LPRN LSFT(KC_8) // (
73#define DE_OSX_RPRN LSFT(KC_9) // )
74#define DE_OSX_EQL LSFT(KC_0) // =
75#define DE_OSX_QST LSFT(DE_OSX_SS) // ?
76#define DE_OSX_GRV LSFT(DE_OSX_ACUT) // `
77#define DE_OSX_ASTR LSFT(DE_OSX_PLUS) // *
78#define DE_OSX_QUOT LSFT(DE_OSX_HASH) // '
79#define DE_OSX_MORE LSFT(DE_OSX_LESS) // >
80#define DE_OSX_COLN LSFT(KC_DOT) // :
81#define DE_OSX_SCLN LSFT(KC_COMM) // ;
82#define DE_OSX_UNDS LSFT(DE_OSX_MINS) // _
83
84// Alt-ed characters
85//#define DE_OSX_SQ2 LALT(KC_2) // ²
86//#define DE_OSX_SQ3 LALT(KC_3) // ³
87#define DE_OSX_LCBR LALT(KC_8) // {
88#define DE_OSX_LBRC LALT(KC_5) // [
89#define DE_OSX_RBRC LALT(KC_6) // ]
90#define DE_OSX_RCBR LALT(KC_9) // }
91#define DE_OSX_BSLS LALT(LSFT(KC_7)) // backslash
92#define DE_OSX_AT LALT(DE_OSX_L) // @
93#define DE_OSX_EURO LALT(KC_E) // €
94#define DE_OSX_TILD LALT(DE_OSX_N) // ~
95#define DE_OSX_PIPE LALT(DE_OSX_7) // |
96
97#endif
diff --git a/quantum/keymap_extras/keymap_neo2.h b/quantum/keymap_extras/keymap_neo2.h
new file mode 100644
index 000000000..80439af34
--- /dev/null
+++ b/quantum/keymap_extras/keymap_neo2.h
@@ -0,0 +1,63 @@
1#ifndef KEYMAP_NEO2
2#define KEYMAP_NEO2
3
4#include "keymap.h"
5#include "keymap_german.h"
6
7#define NEO_A KC_D
8#define NEO_B KC_N
9#define NEO_C KC_R
10#define NEO_D DE_OE
11#define NEO_E KC_F
12#define NEO_F KC_O
13#define NEO_G KC_I
14#define NEO_H KC_U
15#define NEO_I KC_S
16#define NEO_J DE_MINS
17#define NEO_K DE_Z
18#define NEO_L KC_E
19#define NEO_M KC_M
20#define NEO_N KC_J
21#define NEO_O KC_G
22#define NEO_P KC_V
23#define NEO_Q KC_P
24#define NEO_R KC_K
25#define NEO_S KC_H
26#define NEO_T KC_L
27#define NEO_U KC_A
28#define NEO_V KC_W
29#define NEO_W KC_T
30#define NEO_X KC_Q
31#define NEO_Y DE_AE
32#define NEO_Z KC_B
33#define NEO_AE KC_C
34#define NEO_OE KC_X
35#define NEO_UE DE_Y
36#define NEO_SS DE_UE
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
57#define NEO_L1_L KC_CAPS
58#define NEO_L1_R DE_HASH
59
60#define NEO_L2_L DE_LESS
61#define NEO_L2_R DE_ALGR
62
63#endif
diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h
new file mode 100644
index 000000000..3acb8b698
--- /dev/null
+++ b/quantum/keymap_extras/keymap_nordic.h
@@ -0,0 +1,59 @@
1#ifndef KEYMAP_NORDIC_H
2#define KEYMAP_NORDIC_H
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) kc | 0x1400
8#define NO_ALGR KC_RALT
9
10// Normal characters
11#define NO_HALF KC_GRV
12#define NO_PLUS KC_MINS
13#define NO_ACUT KC_EQL
14
15#define NO_AM KC_LBRC
16#define NO_QUOT KC_RBRC
17#define NO_AE KC_SCLN
18#define NO_OSLH KC_QUOT
19#define NO_APOS KC_NUHS
20
21#define NO_LESS KC_NUBS
22#define NO_MINS KC_SLSH
23
24// Shifted characters
25#define NO_SECT LSFT(NO_HALF)
26#define NO_QUO2 LSFT(KC_2)
27#define NO_BULT LSFT(KC_4)
28#define NO_AMP LSFT(KC_6)
29#define NO_SLSH LSFT(KC_7)
30#define NO_LPRN LSFT(KC_8)
31#define NO_RPRN LSFT(KC_9)
32#define NO_EQL LSFT(KC_0)
33#define NO_QUES LSFT(NO_PLUS)
34#define NO_GRV LSFT(NO_ACUT)
35
36#define NO_CIRC LSFT(NO_QUOT)
37
38#define NO_GRTR LSFT(NO_LESS)
39#define NO_SCLN LSFT(KC_COMM)
40#define NO_COLN LSFT(KC_DOT)
41#define NO_UNDS LSFT(NO_MINS)
42
43// Alt Gr-ed characters
44#define NO_AT ALGR(KC_2)
45#define NO_PND ALGR(KC_3)
46#define NO_DLR ALGR(KC_4)
47#define NO_LCBR ALGR(KC_7)
48#define NO_LBRC ALGR(KC_8)
49#define NO_RBRC ALGR(KC_9)
50#define NO_RCBR ALGR(KC_0)
51#define NO_PIPE ALGR(KC_NUBS)
52
53#define NO_EURO ALGR(KC_E)
54#define NO_TILD ALGR(NO_QUOT)
55
56#define NO_BSLS ALGR(KC_MINS)
57#define NO_MU ALGR(KC_M)
58
59#endif
diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h
new file mode 100644
index 000000000..018bfeae5
--- /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(C_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_spanish.h b/quantum/keymap_extras/keymap_spanish.h
new file mode 100644
index 000000000..af76e39fc
--- /dev/null
+++ b/quantum/keymap_extras/keymap_spanish.h
@@ -0,0 +1,62 @@
1#ifndef KEYMAP_SPANISH_H
2#define KEYMAP_SPANISH_H
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) kc | 0x1400
8#define NO_ALGR KC_RALT
9
10// Normal characters
11#define ES_OVRR KC_GRV
12#define ES_APOS KC_MINS
13#define ES_IEXL KC_EQL
14
15#define ES_GRV KC_LBRC
16#define ES_PLUS KC_RBRC
17
18#define ES_NTIL KC_SCLN
19#define ES_ACUT KC_QUOT
20#define ES_CCED KC_NUHS
21
22#define ES_LESS KC_NUBS
23#define ES_MINS KC_SLSH
24
25// Shifted characters
26#define ES_ASML LSFT(ES_OVRR)
27#define ES_QUOT LSFT(KC_2)
28#define ES_OVDT LSFT(KC_3)
29#define ES_AMPR LSFT(KC_6)
30#define ES_SLSH LSFT(KC_7)
31#define ES_LPRN LSFT(KC_8)
32#define ES_RPRN LSFT(KC_9)
33#define ES_EQL LSFT(KC_0)
34#define ES_QUES LSFT(ES_APOS)
35#define ES_IQUE LSFT(ES_IEXL)
36
37#define ES_CIRC LSFT(ES_GRV)
38#define ES_ASTR LSFT(ES_PLUS)
39
40#define ES_UMLT LSFT(ES_GRV)
41
42#define ES_GRTR LSFT(ES_LESS)
43#define ES_SCLN LSFT(ES_COMM)
44#define ES_COLN LSFT(ES_DOT)
45#define ES_UNDS LSFT(ES_MINS)
46
47// Alt Gr-ed characters
48#define ES_BSLS ALGR(ES_OVRR)
49#define ES_PIPE ALGR(KC_1)
50#define ES_AT ALGR(KC_2)
51#define ES_HASH ALGR(KC_3)
52#define ES_TILD ALGR(ES_NTIL)
53#define ES_EURO ALGR(KC_5)
54#define ES_NOT ALGR(KC_6)
55
56#define ES_LBRC ALGR(ES_GRV)
57#define ES_RBRC ALGR(ES_PLUS)
58
59#define ES_LCBR ALGR(ES_ACUT)
60#define ES_RCRB ALGR(ES_CCED)
61
62#endif
diff --git a/quantum/keymap_extras/keymap_uk.h b/quantum/keymap_extras/keymap_uk.h
new file mode 100644
index 000000000..5c5d95179
--- /dev/null
+++ b/quantum/keymap_extras/keymap_uk.h
@@ -0,0 +1,36 @@
1#ifndef KEYMAP_UK_H
2#define KEYMAP_UK_H
3
4#include "keymap.h"
5
6// Alt gr
7#define ALGR(kc) kc | 0x1400
8#define NO_ALGR KC_RALT
9
10// Normal characters
11#define UK_HASH KC_NUHS
12
13#define UK_BSLS KC_NUBS
14
15// Shifted characters
16#define UK_NOT LSFT(KC_GRV)
17#define UK_QUOT LSFT(KC_2)
18#define UK_PND LSFT(KC_3)
19
20#define UK_AT LSFT(KC_QUOT)
21#define UK_TILD LSFT(KC_NUHS)
22
23#define UK_PIPE LSFT(KC_NUBS)
24
25// Alt Gr-ed characters
26#define UK_BRKP ALGR(KC_GRV)
27#define UK_EURO ALGR(KC_4)
28
29#define UK_EACT ALGR(KC_E)
30#define UK_UACT ALGR(KC_U)
31#define UK_IACT ALGR(KC_I)
32#define UK_OACT ALGR(KC_O)
33
34#define UK_AACT ALGR(KC_A)
35
36#endif \ No newline at end of file
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c
new file mode 100755
index 000000000..f20043067
--- /dev/null
+++ b/quantum/light_ws2812.c
@@ -0,0 +1,181 @@
1/*
2* light weight WS2812 lib V2.0b
3*
4* Controls WS2811/WS2812/WS2812B RGB-LEDs
5* Author: Tim (cpldcpu@gmail.com)
6*
7* Jan 18th, 2014 v2.0b Initial Version
8* Nov 29th, 2015 v2.3 Added SK6812RGBW support
9*
10* License: GNU GPL v2 (see License.txt)
11*/
12
13#include "light_ws2812.h"
14#include <avr/interrupt.h>
15#include <avr/io.h>
16#include <util/delay.h>
17#include "debug.h"
18
19// Setleds for standard RGB
20void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
21{
22 ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
23}
24
25void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
26{
27 ws2812_DDRREG |= pinmask; // Enable DDR
28 ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
29 _delay_us(50);
30}
31
32// Setleds for SK6812RGBW
33void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
34{
35 ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR
36 ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin));
37 _delay_us(80);
38}
39
40void ws2812_sendarray(uint8_t *data,uint16_t datlen)
41{
42 ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin));
43}
44
45/*
46 This routine writes an array of bytes with RGB values to the Dataout pin
47 using the fast 800kHz clockless WS2811/2812 protocol.
48*/
49
50// Timing in ns
51#define w_zeropulse 350
52#define w_onepulse 900
53#define w_totalperiod 1250
54
55// Fixed cycles used by the inner loop
56#define w_fixedlow 2
57#define w_fixedhigh 4
58#define w_fixedtotal 8
59
60// Insert NOPs to match the timing, if possible
61#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
62#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
63#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
64
65// w1 - nops between rising edge and falling edge - low
66#define w1 (w_zerocycles-w_fixedlow)
67// w2 nops between fe low and fe high
68#define w2 (w_onecycles-w_fixedhigh-w1)
69// w3 nops to complete loop
70#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
71
72#if w1>0
73 #define w1_nops w1
74#else
75 #define w1_nops 0
76#endif
77
78// The only critical timing parameter is the minimum pulse length of the "0"
79// Warn or throw error if this timing can not be met with current F_CPU settings.
80#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
81#if w_lowtime>550
82 #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
83#elif w_lowtime>450
84 #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
85 #warning "Please consider a higher clockspeed, if possible"
86#endif
87
88#if w2>0
89#define w2_nops w2
90#else
91#define w2_nops 0
92#endif
93
94#if w3>0
95#define w3_nops w3
96#else
97#define w3_nops 0
98#endif
99
100#define w_nop1 "nop \n\t"
101#define w_nop2 "rjmp .+0 \n\t"
102#define w_nop4 w_nop2 w_nop2
103#define w_nop8 w_nop4 w_nop4
104#define w_nop16 w_nop8 w_nop8
105
106void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
107{
108 uint8_t curbyte,ctr,masklo;
109 uint8_t sreg_prev;
110
111 masklo =~maskhi&ws2812_PORTREG;
112 maskhi |= ws2812_PORTREG;
113 sreg_prev=SREG;
114 cli();
115
116 while (datlen--) {
117 curbyte=*data++;
118
119 asm volatile(
120 " ldi %0,8 \n\t"
121 "loop%=: \n\t"
122 " out %2,%3 \n\t" // '1' [01] '0' [01] - re
123#if (w1_nops&1)
124w_nop1
125#endif
126#if (w1_nops&2)
127w_nop2
128#endif
129#if (w1_nops&4)
130w_nop4
131#endif
132#if (w1_nops&8)
133w_nop8
134#endif
135#if (w1_nops&16)
136w_nop16
137#endif
138 " sbrs %1,7 \n\t" // '1' [03] '0' [02]
139 " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
140 " lsl %1 \n\t" // '1' [04] '0' [04]
141#if (w2_nops&1)
142 w_nop1
143#endif
144#if (w2_nops&2)
145 w_nop2
146#endif
147#if (w2_nops&4)
148 w_nop4
149#endif
150#if (w2_nops&8)
151 w_nop8
152#endif
153#if (w2_nops&16)
154 w_nop16
155#endif
156 " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
157#if (w3_nops&1)
158w_nop1
159#endif
160#if (w3_nops&2)
161w_nop2
162#endif
163#if (w3_nops&4)
164w_nop4
165#endif
166#if (w3_nops&8)
167w_nop8
168#endif
169#if (w3_nops&16)
170w_nop16
171#endif
172
173 " dec %0 \n\t" // '1' [+2] '0' [+2]
174 " brne loop%=\n\t" // '1' [+3] '0' [+4]
175 : "=&d" (ctr)
176 : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
177 );
178 }
179
180 SREG=sreg_prev;
181}
diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h
new file mode 100755
index 000000000..54eef22d9
--- /dev/null
+++ b/quantum/light_ws2812.h
@@ -0,0 +1,73 @@
1/*
2 * light weight WS2812 lib include
3 *
4 * Version 2.3 - Nev 29th 2015
5 * Author: Tim (cpldcpu@gmail.com)
6 *
7 * Please do not change this file! All configuration is handled in "ws2812_config.h"
8 *
9 * License: GNU GPL v2 (see License.txt)
10 +
11 */
12
13#ifndef LIGHT_WS2812_H_
14#define LIGHT_WS2812_H_
15
16#include <avr/io.h>
17#include <avr/interrupt.h>
18//#include "ws2812_config.h"
19
20/*
21 * Structure of the LED array
22 *
23 * cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106
24 * cRGBW: RGBW for SK6812RGBW
25 */
26
27struct cRGB { uint8_t g; uint8_t r; uint8_t b; };
28struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
29
30
31
32/* User Interface
33 *
34 * Input:
35 * ledarray: An array of GRB data describing the LED colors
36 * number_of_leds: The number of LEDs to write
37 * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
38 *
39 * The functions will perform the following actions:
40 * - Set the data-out pin as output
41 * - Send out the LED data
42 * - Wait 50�s to reset the LEDs
43 */
44
45void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds);
46void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask);
47void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds);
48
49/*
50 * Old interface / Internal functions
51 *
52 * The functions take a byte-array and send to the data output as WS2812 bitstream.
53 * The length is the number of bytes to send - three per LED.
54 */
55
56void ws2812_sendarray (uint8_t *array,uint16_t length);
57void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
58
59
60/*
61 * Internal defines
62 */
63#ifndef CONCAT
64#define CONCAT(a, b) a ## b
65#endif
66#ifndef CONCAT_EXP
67#define CONCAT_EXP(a, b) CONCAT(a, b)
68#endif
69
70// #define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
71// #define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)
72
73#endif /* LIGHT_WS2812_H_ */
diff --git a/quantum/matrix.c b/quantum/matrix.c
new file mode 100644
index 000000000..3174e0739
--- /dev/null
+++ b/quantum/matrix.c
@@ -0,0 +1,297 @@
1/*
2Copyright 2012 Jun Wako
3Copyright 2014 Jack Humbert
4
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
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include <stdint.h>
19#include <stdbool.h>
20#if defined(__AVR__)
21#include <avr/io.h>
22#endif
23#include "wait.h"
24#include "print.h"
25#include "debug.h"
26#include "util.h"
27#include "matrix.h"
28
29/* Set 0 if debouncing isn't needed */
30
31#ifndef DEBOUNCING_DELAY
32# define DEBOUNCING_DELAY 5
33#endif
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;
38
39/* matrix state(1:on, 0:off) */
40static matrix_row_t matrix[MATRIX_ROWS];
41static matrix_row_t matrix_debouncing[MATRIX_ROWS];
42
43#if DIODE_DIRECTION == ROW2COL
44 static matrix_row_t matrix_reversed[MATRIX_COLS];
45 static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS];
46#endif
47
48#if MATRIX_COLS > 16
49 #define SHIFTER 1UL
50#else
51 #define SHIFTER 1
52#endif
53
54static matrix_row_t read_cols(void);
55static void init_cols(void);
56static void unselect_rows(void);
57static void select_row(uint8_t row);
58
59__attribute__ ((weak))
60void matrix_init_quantum(void) {
61 matrix_init_kb();
62}
63
64__attribute__ ((weak))
65void matrix_scan_quantum(void) {
66 matrix_scan_kb();
67}
68
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}
78
79__attribute__ ((weak))
80void matrix_init_user(void) {
81}
82
83__attribute__ ((weak))
84void matrix_scan_user(void) {
85}
86
87inline
88uint8_t matrix_rows(void) {
89 return MATRIX_ROWS;
90}
91
92inline
93uint8_t matrix_cols(void) {
94 return MATRIX_COLS;
95}
96
97// void matrix_power_up(void) {
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) {
122 // To use PORTF disable JTAG with writing JTD bit twice within four cycles.
123 #ifdef __AVR_ATmega32U4__
124 MCUCR |= _BV(JTD);
125 MCUCR |= _BV(JTD);
126 #endif
127
128 // initialize row and col
129 unselect_rows();
130 init_cols();
131
132 // initialize matrix state: all keys off
133 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
134 matrix[i] = 0;
135 matrix_debouncing[i] = 0;
136 }
137
138 matrix_init_quantum();
139}
140
141uint8_t matrix_scan(void)
142{
143
144#if DIODE_DIRECTION == COL2ROW
145 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
146 select_row(i);
147 wait_us(30); // without this wait read unstable value.
148 matrix_row_t cols = read_cols();
149 if (matrix_debouncing[i] != cols) {
150 matrix_debouncing[i] = cols;
151 if (debouncing) {
152 debug("bounce!: "); debug_hex(debouncing); debug("\n");
153 }
154 debouncing = DEBOUNCING_DELAY;
155 }
156 unselect_rows();
157 }
158
159 if (debouncing) {
160 if (--debouncing) {
161 wait_ms(1);
162 } else {
163 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
164 matrix[i] = matrix_debouncing[i];
165 }
166 }
167 }
168#else
169 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
170 select_row(i);
171 wait_us(30); // without this wait read unstable value.
172 matrix_row_t rows = read_cols();
173 if (matrix_reversed_debouncing[i] != rows) {
174 matrix_reversed_debouncing[i] = rows;
175 if (debouncing) {
176 debug("bounce!: "); debug_hex(debouncing); debug("\n");
177 }
178 debouncing = DEBOUNCING_DELAY;
179 }
180 unselect_rows();
181 }
182
183 if (debouncing) {
184 if (--debouncing) {
185 wait_ms(1);
186 } else {
187 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
188 matrix_reversed[i] = matrix_reversed_debouncing[i];
189 }
190 }
191 }
192 for (uint8_t y = 0; y < MATRIX_ROWS; y++) {
193 matrix_row_t row = 0;
194 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
195 row |= ((matrix_reversed[x] & (1<<y)) >> y) << x;
196 }
197 matrix[y] = row;
198 }
199#endif
200
201 matrix_scan_quantum();
202
203 return 1;
204}
205
206bool matrix_is_modified(void)
207{
208 if (debouncing) return false;
209 return true;
210}
211
212inline
213bool matrix_is_on(uint8_t row, uint8_t col)
214{
215 return (matrix[row] & ((matrix_row_t)1<col));
216}
217
218inline
219matrix_row_t matrix_get_row(uint8_t row)
220{
221 return matrix[row];
222}
223
224void matrix_print(void)
225{
226 print("\nr/c 0123456789ABCDEF\n");
227 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
228 phex(row); print(": ");
229 pbin_reverse16(matrix_get_row(row));
230 print("\n");
231 }
232}
233
234uint8_t matrix_key_count(void)
235{
236 uint8_t count = 0;
237 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
238 count += bitpop16(matrix[i]);
239 }
240 return count;
241}
242
243static void init_cols(void)
244{
245#if DIODE_DIRECTION == COL2ROW
246 for(int x = 0; x < MATRIX_COLS; x++) {
247 int pin = col_pins[x];
248#else
249 for(int x = 0; x < MATRIX_ROWS; x++) {
250 int pin = row_pins[x];
251#endif
252 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
253 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
254 }
255}
256
257static matrix_row_t read_cols(void)
258{
259 matrix_row_t result = 0;
260
261#if DIODE_DIRECTION == COL2ROW
262 for(int x = 0; x < MATRIX_COLS; x++) {
263 int pin = col_pins[x];
264#else
265 for(int x = 0; x < MATRIX_ROWS; x++) {
266 int pin = row_pins[x];
267#endif
268 result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x);
269 }
270 return result;
271}
272
273static void unselect_rows(void)
274{
275#if DIODE_DIRECTION == COL2ROW
276 for(int x = 0; x < MATRIX_ROWS; x++) {
277 int pin = row_pins[x];
278#else
279 for(int x = 0; x < MATRIX_COLS; x++) {
280 int pin = col_pins[x];
281#endif
282 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
283 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
284 }
285}
286
287static void select_row(uint8_t row)
288{
289
290#if DIODE_DIRECTION == COL2ROW
291 int pin = row_pins[row];
292#else
293 int pin = col_pins[row];
294#endif
295 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF);
296 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF);
297}
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..d6ab9c626
--- /dev/null
+++ b/quantum/process_keycode/process_midi.c
@@ -0,0 +1,66 @@
1#include "process_midi.h"
2
3bool midi_activated = false;
4uint8_t starting_note = 0x0C;
5int 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 music_scale_user();
11 return false;
12 }
13
14 if (keycode == MI_OFF && record->event.pressed) {
15 midi_activated = false;
16 midi_send_cc(&midi_device, 0, 0x7B, 0);
17 return false;
18 }
19
20 if (midi_activated) {
21 if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) {
22 if (record->event.pressed) {
23 starting_note++; // Change key
24 midi_send_cc(&midi_device, 0, 0x7B, 0);
25 }
26 return false;
27 }
28 if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) {
29 if (record->event.pressed) {
30 starting_note--; // Change key
31 midi_send_cc(&midi_device, 0, 0x7B, 0);
32 }
33 return false;
34 }
35 if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
36 offset++; // Change scale
37 midi_send_cc(&midi_device, 0, 0x7B, 0);
38 return false;
39 }
40 if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
41 offset--; // Change scale
42 midi_send_cc(&midi_device, 0, 0x7B, 0);
43 return false;
44 }
45 // basic
46 // uint8_t note = (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row);
47 // advanced
48 // uint8_t note = (starting_note + record->event.key.col + offset)+12*(MATRIX_ROWS - record->event.key.row);
49 // guitar
50 uint8_t note = (starting_note + record->event.key.col + offset)+5*(MATRIX_ROWS - record->event.key.row);
51 // violin
52 // uint8_t note = (starting_note + record->event.key.col + offset)+7*(MATRIX_ROWS - record->event.key.row);
53
54 if (record->event.pressed) {
55 // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
56 midi_send_noteon(&midi_device, 0, note, 127);
57 } else {
58 // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
59 midi_send_noteoff(&midi_device, 0, note, 127);
60 }
61
62 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
63 return false;
64 }
65 return true;
66} \ No newline at end of file
diff --git a/quantum/process_keycode/process_midi.h b/quantum/process_keycode/process_midi.h
new file mode 100644
index 000000000..acd4fc1b1
--- /dev/null
+++ b/quantum/process_keycode/process_midi.h
@@ -0,0 +1,207 @@
1#ifndef PROCESS_MIDI_H
2#define PROCESS_MIDI_H
3
4#include "quantum.h"
5
6bool process_midi(uint16_t keycode, keyrecord_t *record);
7
8#define MIDI(n) ((n) | 0x6000)
9#define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000
10
11#define CHNL(note, channel) (note + (channel << 8))
12
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), \
14 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \
15 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \
16 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \
17 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), }
18
19#define N_CN1 (0x600C + (12 * -1) + 0 )
20#define N_CN1S (0x600C + (12 * -1) + 1 )
21#define N_DN1F (0x600C + (12 * -1) + 1 )
22#define N_DN1 (0x600C + (12 * -1) + 2 )
23#define N_DN1S (0x600C + (12 * -1) + 3 )
24#define N_EN1F (0x600C + (12 * -1) + 3 )
25#define N_EN1 (0x600C + (12 * -1) + 4 )
26#define N_FN1 (0x600C + (12 * -1) + 5 )
27#define N_FN1S (0x600C + (12 * -1) + 6 )
28#define N_GN1F (0x600C + (12 * -1) + 6 )
29#define N_GN1 (0x600C + (12 * -1) + 7 )
30#define N_GN1S (0x600C + (12 * -1) + 8 )
31#define N_AN1F (0x600C + (12 * -1) + 8 )
32#define N_AN1 (0x600C + (12 * -1) + 9 )
33#define N_AN1S (0x600C + (12 * -1) + 10)
34#define N_BN1F (0x600C + (12 * -1) + 10)
35#define N_BN1 (0x600C + (12 * -1) + 11)
36#define N_C0 (0x600C + (12 * 0) + 0 )
37#define N_C0S (0x600C + (12 * 0) + 1 )
38#define N_D0F (0x600C + (12 * 0) + 1 )
39#define N_D0 (0x600C + (12 * 0) + 2 )
40#define N_D0S (0x600C + (12 * 0) + 3 )
41#define N_E0F (0x600C + (12 * 0) + 3 )
42#define N_E0 (0x600C + (12 * 0) + 4 )
43#define N_F0 (0x600C + (12 * 0) + 5 )
44#define N_F0S (0x600C + (12 * 0) + 6 )
45#define N_G0F (0x600C + (12 * 0) + 6 )
46#define N_G0 (0x600C + (12 * 0) + 7 )
47#define N_G0S (0x600C + (12 * 0) + 8 )
48#define N_A0F (0x600C + (12 * 0) + 8 )
49#define N_A0 (0x600C + (12 * 0) + 9 )
50#define N_A0S (0x600C + (12 * 0) + 10)
51#define N_B0F (0x600C + (12 * 0) + 10)
52#define N_B0 (0x600C + (12 * 0) + 11)
53#define N_C1 (0x600C + (12 * 1) + 0 )
54#define N_C1S (0x600C + (12 * 1) + 1 )
55#define N_D1F (0x600C + (12 * 1) + 1 )
56#define N_D1 (0x600C + (12 * 1) + 2 )
57#define N_D1S (0x600C + (12 * 1) + 3 )
58#define N_E1F (0x600C + (12 * 1) + 3 )
59#define N_E1 (0x600C + (12 * 1) + 4 )
60#define N_F1 (0x600C + (12 * 1) + 5 )
61#define N_F1S (0x600C + (12 * 1) + 6 )
62#define N_G1F (0x600C + (12 * 1) + 6 )
63#define N_G1 (0x600C + (12 * 1) + 7 )
64#define N_G1S (0x600C + (12 * 1) + 8 )
65#define N_A1F (0x600C + (12 * 1) + 8 )
66#define N_A1 (0x600C + (12 * 1) + 9 )
67#define N_A1S (0x600C + (12 * 1) + 10)
68#define N_B1F (0x600C + (12 * 1) + 10)
69#define N_B1 (0x600C + (12 * 1) + 11)
70#define N_C2 (0x600C + (12 * 2) + 0 )
71#define N_C2S (0x600C + (12 * 2) + 1 )
72#define N_D2F (0x600C + (12 * 2) + 1 )
73#define N_D2 (0x600C + (12 * 2) + 2 )
74#define N_D2S (0x600C + (12 * 2) + 3 )
75#define N_E2F (0x600C + (12 * 2) + 3 )
76#define N_E2 (0x600C + (12 * 2) + 4 )
77#define N_F2 (0x600C + (12 * 2) + 5 )
78#define N_F2S (0x600C + (12 * 2) + 6 )
79#define N_G2F (0x600C + (12 * 2) + 6 )
80#define N_G2 (0x600C + (12 * 2) + 7 )
81#define N_G2S (0x600C + (12 * 2) + 8 )
82#define N_A2F (0x600C + (12 * 2) + 8 )
83#define N_A2 (0x600C + (12 * 2) + 9 )
84#define N_A2S (0x600C + (12 * 2) + 10)
85#define N_B2F (0x600C + (12 * 2) + 10)
86#define N_B2 (0x600C + (12 * 2) + 11)
87#define N_C3 (0x600C + (12 * 3) + 0 )
88#define N_C3S (0x600C + (12 * 3) + 1 )
89#define N_D3F (0x600C + (12 * 3) + 1 )
90#define N_D3 (0x600C + (12 * 3) + 2 )
91#define N_D3S (0x600C + (12 * 3) + 3 )
92#define N_E3F (0x600C + (12 * 3) + 3 )
93#define N_E3 (0x600C + (12 * 3) + 4 )
94#define N_F3 (0x600C + (12 * 3) + 5 )
95#define N_F3S (0x600C + (12 * 3) + 6 )
96#define N_G3F (0x600C + (12 * 3) + 6 )
97#define N_G3 (0x600C + (12 * 3) + 7 )
98#define N_G3S (0x600C + (12 * 3) + 8 )
99#define N_A3F (0x600C + (12 * 3) + 8 )
100#define N_A3 (0x600C + (12 * 3) + 9 )
101#define N_A3S (0x600C + (12 * 3) + 10)
102#define N_B3F (0x600C + (12 * 3) + 10)
103#define N_B3 (0x600C + (12 * 3) + 11)
104#define N_C4 (0x600C + (12 * 4) + 0 )
105#define N_C4S (0x600C + (12 * 4) + 1 )
106#define N_D4F (0x600C + (12 * 4) + 1 )
107#define N_D4 (0x600C + (12 * 4) + 2 )
108#define N_D4S (0x600C + (12 * 4) + 3 )
109#define N_E4F (0x600C + (12 * 4) + 3 )
110#define N_E4 (0x600C + (12 * 4) + 4 )
111#define N_F4 (0x600C + (12 * 4) + 5 )
112#define N_F4S (0x600C + (12 * 4) + 6 )
113#define N_G4F (0x600C + (12 * 4) + 6 )
114#define N_G4 (0x600C + (12 * 4) + 7 )
115#define N_G4S (0x600C + (12 * 4) + 8 )
116#define N_A4F (0x600C + (12 * 4) + 8 )
117#define N_A4 (0x600C + (12 * 4) + 9 )
118#define N_A4S (0x600C + (12 * 4) + 10)
119#define N_B4F (0x600C + (12 * 4) + 10)
120#define N_B4 (0x600C + (12 * 4) + 11)
121#define N_C5 (0x600C + (12 * 5) + 0 )
122#define N_C5S (0x600C + (12 * 5) + 1 )
123#define N_D5F (0x600C + (12 * 5) + 1 )
124#define N_D5 (0x600C + (12 * 5) + 2 )
125#define N_D5S (0x600C + (12 * 5) + 3 )
126#define N_E5F (0x600C + (12 * 5) + 3 )
127#define N_E5 (0x600C + (12 * 5) + 4 )
128#define N_F5 (0x600C + (12 * 5) + 5 )
129#define N_F5S (0x600C + (12 * 5) + 6 )
130#define N_G5F (0x600C + (12 * 5) + 6 )
131#define N_G5 (0x600C + (12 * 5) + 7 )
132#define N_G5S (0x600C + (12 * 5) + 8 )
133#define N_A5F (0x600C + (12 * 5) + 8 )
134#define N_A5 (0x600C + (12 * 5) + 9 )
135#define N_A5S (0x600C + (12 * 5) + 10)
136#define N_B5F (0x600C + (12 * 5) + 10)
137#define N_B5 (0x600C + (12 * 5) + 11)
138#define N_C6 (0x600C + (12 * 6) + 0 )
139#define N_C6S (0x600C + (12 * 6) + 1 )
140#define N_D6F (0x600C + (12 * 6) + 1 )
141#define N_D6 (0x600C + (12 * 6) + 2 )
142#define N_D6S (0x600C + (12 * 6) + 3 )
143#define N_E6F (0x600C + (12 * 6) + 3 )
144#define N_E6 (0x600C + (12 * 6) + 4 )
145#define N_F6 (0x600C + (12 * 6) + 5 )
146#define N_F6S (0x600C + (12 * 6) + 6 )
147#define N_G6F (0x600C + (12 * 6) + 6 )
148#define N_G6 (0x600C + (12 * 6) + 7 )
149#define N_G6S (0x600C + (12 * 6) + 8 )
150#define N_A6F (0x600C + (12 * 6) + 8 )
151#define N_A6 (0x600C + (12 * 6) + 9 )
152#define N_A6S (0x600C + (12 * 6) + 10)
153#define N_B6F (0x600C + (12 * 6) + 10)
154#define N_B6 (0x600C + (12 * 6) + 11)
155#define N_C7 (0x600C + (12 * 7) + 0 )
156#define N_C7S (0x600C + (12 * 7) + 1 )
157#define N_D7F (0x600C + (12 * 7) + 1 )
158#define N_D7 (0x600C + (12 * 7) + 2 )
159#define N_D7S (0x600C + (12 * 7) + 3 )
160#define N_E7F (0x600C + (12 * 7) + 3 )
161#define N_E7 (0x600C + (12 * 7) + 4 )
162#define N_F7 (0x600C + (12 * 7) + 5 )
163#define N_F7S (0x600C + (12 * 7) + 6 )
164#define N_G7F (0x600C + (12 * 7) + 6 )
165#define N_G7 (0x600C + (12 * 7) + 7 )
166#define N_G7S (0x600C + (12 * 7) + 8 )
167#define N_A7F (0x600C + (12 * 7) + 8 )
168#define N_A7 (0x600C + (12 * 7) + 9 )
169#define N_A7S (0x600C + (12 * 7) + 10)
170#define N_B7F (0x600C + (12 * 7) + 10)
171#define N_B7 (0x600C + (12 * 7) + 11)
172#define N_C8 (0x600C + (12 * 8) + 0 )
173#define N_C8S (0x600C + (12 * 8) + 1 )
174#define N_D8F (0x600C + (12 * 8) + 1 )
175#define N_D8 (0x600C + (12 * 8) + 2 )
176#define N_D8S (0x600C + (12 * 8) + 3 )
177#define N_E8F (0x600C + (12 * 8) + 3 )
178#define N_E8 (0x600C + (12 * 8) + 4 )
179#define N_F8 (0x600C + (12 * 8) + 5 )
180#define N_F8S (0x600C + (12 * 8) + 6 )
181#define N_G8F (0x600C + (12 * 8) + 6 )
182#define N_G8 (0x600C + (12 * 8) + 7 )
183#define N_G8S (0x600C + (12 * 8) + 8 )
184#define N_A8F (0x600C + (12 * 8) + 8 )
185#define N_A8 (0x600C + (12 * 8) + 9 )
186#define N_A8S (0x600C + (12 * 8) + 10)
187#define N_B8F (0x600C + (12 * 8) + 10)
188#define N_B8 (0x600C + (12 * 8) + 11)
189#define N_C8 (0x600C + (12 * 8) + 0 )
190#define N_C8S (0x600C + (12 * 8) + 1 )
191#define N_D8F (0x600C + (12 * 8) + 1 )
192#define N_D8 (0x600C + (12 * 8) + 2 )
193#define N_D8S (0x600C + (12 * 8) + 3 )
194#define N_E8F (0x600C + (12 * 8) + 3 )
195#define N_E8 (0x600C + (12 * 8) + 4 )
196#define N_F8 (0x600C + (12 * 8) + 5 )
197#define N_F8S (0x600C + (12 * 8) + 6 )
198#define N_G8F (0x600C + (12 * 8) + 6 )
199#define N_G8 (0x600C + (12 * 8) + 7 )
200#define N_G8S (0x600C + (12 * 8) + 8 )
201#define N_A8F (0x600C + (12 * 8) + 8 )
202#define N_A8 (0x600C + (12 * 8) + 9 )
203#define N_A8S (0x600C + (12 * 8) + 10)
204#define N_B8F (0x600C + (12 * 8) + 10)
205#define N_B8 (0x600C + (12 * 8) + 11)
206
207#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c
new file mode 100644
index 000000000..c8f3ddb90
--- /dev/null
+++ b/quantum/process_keycode/process_music.c
@@ -0,0 +1,171 @@
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_playing = false;
10static float music_sequence[16] = {0};
11static uint8_t music_sequence_count = 0;
12static uint8_t music_sequence_position = 0;
13
14static uint16_t music_sequence_timer = 0;
15static uint16_t music_sequence_interval = 100;
16
17bool process_music(uint16_t keycode, keyrecord_t *record) {
18
19 if (keycode == AU_ON && record->event.pressed) {
20 audio_on();
21 return false;
22 }
23
24 if (keycode == AU_OFF && record->event.pressed) {
25 audio_off();
26 return false;
27 }
28
29 if (keycode == AU_TOG && record->event.pressed) {
30 if (is_audio_on())
31 {
32 audio_off();
33 }
34 else
35 {
36 audio_on();
37 }
38 return false;
39 }
40
41 if (keycode == MU_ON && record->event.pressed) {
42 music_on();
43 return false;
44 }
45
46 if (keycode == MU_OFF && record->event.pressed) {
47 music_off();
48 return false;
49 }
50
51 if (keycode == MU_TOG && record->event.pressed) {
52 if (music_activated)
53 {
54 music_off();
55 }
56 else
57 {
58 music_on();
59 }
60 return false;
61 }
62
63 if (keycode == MUV_IN && record->event.pressed) {
64 voice_iterate();
65 music_scale_user();
66 return false;
67 }
68
69 if (keycode == MUV_DE && record->event.pressed) {
70 voice_deiterate();
71 music_scale_user();
72 return false;
73 }
74
75 if (music_activated) {
76
77 if (keycode == KC_LCTL && record->event.pressed) { // Start recording
78 stop_all_notes();
79 music_sequence_recording = true;
80 music_sequence_playing = false;
81 music_sequence_count = 0;
82 return false;
83 }
84
85 if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing
86 stop_all_notes();
87 music_sequence_recording = false;
88 music_sequence_playing = false;
89 return false;
90 }
91
92 if (keycode == KC_LGUI && record->event.pressed) { // Start playing
93 stop_all_notes();
94 music_sequence_recording = false;
95 music_sequence_playing = true;
96 music_sequence_position = 0;
97 music_sequence_timer = 0;
98 return false;
99 }
100
101 if (keycode == KC_UP) {
102 if (record->event.pressed)
103 music_sequence_interval-=10;
104 return false;
105 }
106
107 if (keycode == KC_DOWN) {
108 if (record->event.pressed)
109 music_sequence_interval+=10;
110 return false;
111 }
112
113 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));
114 if (record->event.pressed) {
115 play_note(freq, 0xF);
116 if (music_sequence_recording) {
117 music_sequence[music_sequence_count] = freq;
118 music_sequence_count++;
119 }
120 } else {
121 stop_note(freq);
122 }
123
124 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
125 return false;
126 }
127 return true;
128}
129
130bool is_music_on(void) {
131 return (music_activated != 0);
132}
133
134void music_toggle(void) {
135 if (!music_activated) {
136 music_on();
137 } else {
138 music_off();
139 }
140}
141
142void music_on(void) {
143 music_activated = 1;
144 music_on_user();
145}
146
147void music_off(void) {
148 music_activated = 0;
149 stop_all_notes();
150}
151
152
153__attribute__ ((weak))
154void music_on_user() {}
155
156__attribute__ ((weak))
157void audio_on_user() {}
158
159__attribute__ ((weak))
160void music_scale_user() {}
161
162void matrix_scan_music(void) {
163 if (music_sequence_playing) {
164 if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) {
165 music_sequence_timer = timer_read();
166 stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]);
167 play_note(music_sequence[music_sequence_position], 0xF);
168 music_sequence_position = (music_sequence_position + 1) % music_sequence_count;
169 }
170 }
171}
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..9b172e1b6
--- /dev/null
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -0,0 +1,90 @@
1#include "quantum.h"
2
3static qk_tap_dance_state_t qk_tap_dance_state;
4
5static void _process_tap_dance_action_pair (qk_tap_dance_state_t *state,
6 uint16_t kc1, uint16_t kc2) {
7 uint16_t kc;
8
9 if (state->count == 0)
10 return;
11
12 kc = (state->count == 1) ? kc1 : kc2;
13
14 register_code (kc);
15 unregister_code (kc);
16
17 if (state->count >= 2) {
18 reset_tap_dance (state);
19 }
20}
21
22static void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
23 qk_tap_dance_user_fn_t fn)
24{
25 fn(state);
26}
27
28void process_tap_dance_action (uint16_t keycode)
29{
30 uint16_t idx = keycode - QK_TAP_DANCE;
31 qk_tap_dance_action_t action;
32
33 action = tap_dance_actions[idx];
34
35 switch (action.type) {
36 case QK_TAP_DANCE_TYPE_PAIR:
37 _process_tap_dance_action_pair (&qk_tap_dance_state,
38 action.pair.kc1, action.pair.kc2);
39 break;
40 case QK_TAP_DANCE_TYPE_FN:
41 _process_tap_dance_action_fn (&qk_tap_dance_state, action.fn);
42 break;
43
44 default:
45 break;
46 }
47}
48
49bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
50 bool r = true;
51
52 switch(keycode) {
53 case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
54 if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) {
55 process_tap_dance_action (qk_tap_dance_state.keycode);
56 } else {
57 r = false;
58 }
59
60 if (record->event.pressed) {
61 qk_tap_dance_state.keycode = keycode;
62 qk_tap_dance_state.timer = timer_read ();
63 qk_tap_dance_state.count++;
64 }
65 break;
66
67 default:
68 if (qk_tap_dance_state.keycode) {
69 process_tap_dance_action (qk_tap_dance_state.keycode);
70
71 reset_tap_dance (&qk_tap_dance_state);
72 }
73 break;
74 }
75
76 return r;
77}
78
79void matrix_scan_tap_dance () {
80 if (qk_tap_dance_state.keycode && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) {
81 process_tap_dance_action (qk_tap_dance_state.keycode);
82
83 reset_tap_dance (&qk_tap_dance_state);
84 }
85}
86
87void reset_tap_dance (qk_tap_dance_state_t *state) {
88 state->keycode = 0;
89 state->count = 0;
90}
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
new file mode 100644
index 000000000..b9d7c7fcf
--- /dev/null
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -0,0 +1,62 @@
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} qk_tap_dance_state_t;
15
16#define TD(n) (QK_TAP_DANCE + n)
17
18typedef enum
19{
20 QK_TAP_DANCE_TYPE_PAIR,
21 QK_TAP_DANCE_TYPE_FN,
22} qk_tap_dance_type_t;
23
24typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state);
25
26typedef struct
27{
28 qk_tap_dance_type_t type;
29 union {
30 struct {
31 uint16_t kc1;
32 uint16_t kc2;
33 } pair;
34 qk_tap_dance_user_fn_t fn;
35 };
36} qk_tap_dance_action_t;
37
38#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \
39 .type = QK_TAP_DANCE_TYPE_PAIR, \
40 .pair = { kc1, kc2 } \
41 }
42
43#define ACTION_TAP_DANCE_FN(user_fn) { \
44 .type = QK_TAP_DANCE_TYPE_FN, \
45 .fn = user_fn \
46 }
47
48extern const qk_tap_dance_action_t tap_dance_actions[];
49
50/* To be used internally */
51
52bool process_tap_dance(uint16_t keycode, keyrecord_t *record);
53void matrix_scan_tap_dance (void);
54void reset_tap_dance (qk_tap_dance_state_t *state);
55
56#else
57
58#define TD(n) KC_NO
59
60#endif
61
62#endif
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
new file mode 100644
index 000000000..ad5d7f86b
--- /dev/null
+++ b/quantum/process_keycode/process_unicode.c
@@ -0,0 +1,57 @@
1#include "process_unicode.h"
2
3static uint8_t input_mode;
4
5uint16_t hex_to_keycode(uint8_t hex)
6{
7 if (hex == 0x0) {
8 return KC_0;
9 } else if (hex < 0xA) {
10 return KC_1 + (hex - 0x1);
11 } else {
12 return KC_A + (hex - 0xA);
13 }
14}
15
16void set_unicode_mode(uint8_t os_target)
17{
18 input_mode = os_target;
19}
20
21bool process_unicode(uint16_t keycode, keyrecord_t *record) {
22 if (keycode > QK_UNICODE && record->event.pressed) {
23 uint16_t unicode = keycode & 0x7FFF;
24 switch(input_mode) {
25 case UC_OSX:
26 register_code(KC_LALT);
27 break;
28 case UC_LNX:
29 register_code(KC_LCTL);
30 register_code(KC_LSFT);
31 register_code(KC_U);
32 unregister_code(KC_U);
33 break;
34 case UC_WIN:
35 register_code(KC_LALT);
36 register_code(KC_PPLS);
37 unregister_code(KC_PPLS);
38 break;
39 }
40 for(int i = 3; i >= 0; i--) {
41 uint8_t digit = ((unicode >> (i*4)) & 0xF);
42 register_code(hex_to_keycode(digit));
43 unregister_code(hex_to_keycode(digit));
44 }
45 switch(input_mode) {
46 case UC_OSX:
47 case UC_WIN:
48 unregister_code(KC_LALT);
49 break;
50 case UC_LNX:
51 unregister_code(KC_LCTL);
52 unregister_code(KC_LSFT);
53 break;
54 }
55 }
56 return true;
57} \ No newline at end of file
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h
new file mode 100644
index 000000000..ca17f8f66
--- /dev/null
+++ b/quantum/process_keycode/process_unicode.h
@@ -0,0 +1,122 @@
1#ifndef PROCESS_UNICODE_H
2#define PROCESS_UNICODE_H
3
4#include "quantum.h"
5
6#define UC_OSX 0
7#define UC_LNX 1
8#define UC_WIN 2
9#define UC_BSD 3
10
11void set_unicode_input_mode(uint8_t os_target);
12
13bool process_unicode(uint16_t keycode, keyrecord_t *record);
14
15#define UC_BSPC UC(0x0008)
16
17#define UC_SPC UC(0x0020)
18
19#define UC_EXLM UC(0x0021)
20#define UC_DQUT UC(0x0022)
21#define UC_HASH UC(0x0023)
22#define UC_DLR UC(0x0024)
23#define UC_PERC UC(0x0025)
24#define UC_AMPR UC(0x0026)
25#define UC_QUOT UC(0x0027)
26#define UC_LPRN UC(0x0028)
27#define UC_RPRN UC(0x0029)
28#define UC_ASTR UC(0x002A)
29#define UC_PLUS UC(0x002B)
30#define UC_COMM UC(0x002C)
31#define UC_DASH UC(0x002D)
32#define UC_DOT UC(0x002E)
33#define UC_SLSH UC(0x002F)
34
35#define UC_0 UC(0x0030)
36#define UC_1 UC(0x0031)
37#define UC_2 UC(0x0032)
38#define UC_3 UC(0x0033)
39#define UC_4 UC(0x0034)
40#define UC_5 UC(0x0035)
41#define UC_6 UC(0x0036)
42#define UC_7 UC(0x0037)
43#define UC_8 UC(0x0038)
44#define UC_9 UC(0x0039)
45
46#define UC_COLN UC(0x003A)
47#define UC_SCLN UC(0x003B)
48#define UC_LT UC(0x003C)
49#define UC_EQL UC(0x003D)
50#define UC_GT UC(0x003E)
51#define UC_QUES UC(0x003F)
52#define UC_AT UC(0x0040)
53
54#define UC_A UC(0x0041)
55#define UC_B UC(0x0042)
56#define UC_C UC(0x0043)
57#define UC_D UC(0x0044)
58#define UC_E UC(0x0045)
59#define UC_F UC(0x0046)
60#define UC_G UC(0x0047)
61#define UC_H UC(0x0048)
62#define UC_I UC(0x0049)
63#define UC_J UC(0x004A)
64#define UC_K UC(0x004B)
65#define UC_L UC(0x004C)
66#define UC_M UC(0x004D)
67#define UC_N UC(0x004E)
68#define UC_O UC(0x004F)
69#define UC_P UC(0x0050)
70#define UC_Q UC(0x0051)
71#define UC_R UC(0x0052)
72#define UC_S UC(0x0053)
73#define UC_T UC(0x0054)
74#define UC_U UC(0x0055)
75#define UC_V UC(0x0056)
76#define UC_W UC(0x0057)
77#define UC_X UC(0x0058)
78#define UC_Y UC(0x0059)
79#define UC_Z UC(0x005A)
80
81#define UC_LBRC UC(0x005B)
82#define UC_BSLS UC(0x005C)
83#define UC_RBRC UC(0x005D)
84#define UC_CIRM UC(0x005E)
85#define UC_UNDR UC(0x005F)
86
87#define UC_GRV UC(0x0060)
88
89#define UC_a UC(0x0061)
90#define UC_b UC(0x0062)
91#define UC_c UC(0x0063)
92#define UC_d UC(0x0064)
93#define UC_e UC(0x0065)
94#define UC_f UC(0x0066)
95#define UC_g UC(0x0067)
96#define UC_h UC(0x0068)
97#define UC_i UC(0x0069)
98#define UC_j UC(0x006A)
99#define UC_k UC(0x006B)
100#define UC_l UC(0x006C)
101#define UC_m UC(0x006D)
102#define UC_n UC(0x006E)
103#define UC_o UC(0x006F)
104#define UC_p UC(0x0070)
105#define UC_q UC(0x0071)
106#define UC_r UC(0x0072)
107#define UC_s UC(0x0073)
108#define UC_t UC(0x0074)
109#define UC_u UC(0x0075)
110#define UC_v UC(0x0076)
111#define UC_w UC(0x0077)
112#define UC_x UC(0x0078)
113#define UC_y UC(0x0079)
114#define UC_z UC(0x007A)
115
116#define UC_LCBR UC(0x007B)
117#define UC_PIPE UC(0x007C)
118#define UC_RCBR UC(0x007D)
119#define UC_TILD UC(0x007E)
120#define UC_DEL UC(0x007F)
121
122#endif \ No newline at end of file
diff --git a/quantum/quantum.c b/quantum/quantum.c
new file mode 100644
index 000000000..d59bd5a3f
--- /dev/null
+++ b/quantum/quantum.c
@@ -0,0 +1,717 @@
1#include "quantum.h"
2
3__attribute__ ((weak))
4bool process_action_kb(keyrecord_t *record) {
5 return true;
6}
7
8__attribute__ ((weak))
9bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
10 return process_record_user(keycode, record);
11}
12
13__attribute__ ((weak))
14bool process_record_user(uint16_t keycode, keyrecord_t *record) {
15 return true;
16}
17
18// Shift / paren setup
19
20#ifndef LSPO_KEY
21 #define LSPO_KEY KC_9
22#endif
23#ifndef RSPC_KEY
24 #define RSPC_KEY KC_0
25#endif
26
27static bool shift_interrupted[2] = {0, 0};
28
29bool process_record_quantum(keyrecord_t *record) {
30
31 /* This gets the keycode from the key pressed */
32 keypos_t key = record->event.key;
33 uint16_t keycode;
34
35 #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
36 uint8_t layer;
37
38 if (record->event.pressed) {
39 layer = layer_switch_get_layer(key);
40 update_source_layers_cache(key, layer);
41 } else {
42 layer = read_source_layers_cache(key);
43 }
44 keycode = keymap_key_to_keycode(layer, key);
45 #else
46 keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
47 #endif
48
49 // This is how you use actions here
50 // if (keycode == KC_LEAD) {
51 // action_t action;
52 // action.code = ACTION_DEFAULT_LAYER_SET(0);
53 // process_action(record, action);
54 // return false;
55 // }
56
57 if (!(
58 process_record_kb(keycode, record) &&
59 #ifdef MIDI_ENABLE
60 process_midi(keycode, record) &&
61 #endif
62 #ifdef AUDIO_ENABLE
63 process_music(keycode, record) &&
64 #endif
65 #ifdef TAP_DANCE_ENABLE
66 process_tap_dance(keycode, record) &&
67 #endif
68 #ifndef DISABLE_LEADER
69 process_leader(keycode, record) &&
70 #endif
71 #ifndef DISABLE_CHORDING
72 process_chording(keycode, record) &&
73 #endif
74 #ifdef UNICODE_ENABLE
75 process_unicode(keycode, record) &&
76 #endif
77 true)) {
78 return false;
79 }
80
81 // Shift / paren setup
82
83 switch(keycode) {
84 case RESET:
85 if (record->event.pressed) {
86 clear_keyboard();
87 #ifdef AUDIO_ENABLE
88 stop_all_notes();
89 shutdown_user();
90 #endif
91 wait_ms(250);
92 #ifdef ATREUS_ASTAR
93 *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific
94 #endif
95 bootloader_jump();
96 return false;
97 }
98 break;
99 case DEBUG:
100 if (record->event.pressed) {
101 print("\nDEBUG: enabled.\n");
102 debug_enable = true;
103 return false;
104 }
105 break;
106 case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_UNSWAP_ALT_GUI:
107 if (record->event.pressed) {
108 // MAGIC actions (BOOTMAGIC without the boot)
109 if (!eeconfig_is_enabled()) {
110 eeconfig_init();
111 }
112 /* keymap config */
113 keymap_config.raw = eeconfig_read_keymap();
114 if (keycode == MAGIC_SWAP_CONTROL_CAPSLOCK) {
115 keymap_config.swap_control_capslock = 1;
116 } else if (keycode == MAGIC_CAPSLOCK_TO_CONTROL) {
117 keymap_config.capslock_to_control = 1;
118 } else if (keycode == MAGIC_SWAP_LALT_LGUI) {
119 keymap_config.swap_lalt_lgui = 1;
120 } else if (keycode == MAGIC_SWAP_RALT_RGUI) {
121 keymap_config.swap_ralt_rgui = 1;
122 } else if (keycode == MAGIC_NO_GUI) {
123 keymap_config.no_gui = 1;
124 } else if (keycode == MAGIC_SWAP_GRAVE_ESC) {
125 keymap_config.swap_grave_esc = 1;
126 } else if (keycode == MAGIC_SWAP_BACKSLASH_BACKSPACE) {
127 keymap_config.swap_backslash_backspace = 1;
128 } else if (keycode == MAGIC_HOST_NKRO) {
129 keymap_config.nkro = 1;
130 } else if (keycode == MAGIC_SWAP_ALT_GUI) {
131 keymap_config.swap_lalt_lgui = 1;
132 keymap_config.swap_ralt_rgui = 1;
133 }
134 /* UNs */
135 else if (keycode == MAGIC_UNSWAP_CONTROL_CAPSLOCK) {
136 keymap_config.swap_control_capslock = 0;
137 } else if (keycode == MAGIC_UNCAPSLOCK_TO_CONTROL) {
138 keymap_config.capslock_to_control = 0;
139 } else if (keycode == MAGIC_UNSWAP_LALT_LGUI) {
140 keymap_config.swap_lalt_lgui = 0;
141 } else if (keycode == MAGIC_UNSWAP_RALT_RGUI) {
142 keymap_config.swap_ralt_rgui = 0;
143 } else if (keycode == MAGIC_UNNO_GUI) {
144 keymap_config.no_gui = 0;
145 } else if (keycode == MAGIC_UNSWAP_GRAVE_ESC) {
146 keymap_config.swap_grave_esc = 0;
147 } else if (keycode == MAGIC_UNSWAP_BACKSLASH_BACKSPACE) {
148 keymap_config.swap_backslash_backspace = 0;
149 } else if (keycode == MAGIC_UNHOST_NKRO) {
150 keymap_config.nkro = 0;
151 } else if (keycode == MAGIC_UNSWAP_ALT_GUI) {
152 keymap_config.swap_lalt_lgui = 0;
153 keymap_config.swap_ralt_rgui = 0;
154 }
155 eeconfig_update_keymap(keymap_config.raw);
156 return false;
157 }
158 break;
159 case KC_LSPO: {
160 if (record->event.pressed) {
161 shift_interrupted[0] = false;
162 register_mods(MOD_BIT(KC_LSFT));
163 }
164 else {
165 if (!shift_interrupted[0]) {
166 register_code(LSPO_KEY);
167 unregister_code(LSPO_KEY);
168 }
169 unregister_mods(MOD_BIT(KC_LSFT));
170 }
171 return false;
172 break;
173 }
174
175 case KC_RSPC: {
176 if (record->event.pressed) {
177 shift_interrupted[1] = false;
178 register_mods(MOD_BIT(KC_RSFT));
179 }
180 else {
181 if (!shift_interrupted[1]) {
182 register_code(RSPC_KEY);
183 unregister_code(RSPC_KEY);
184 }
185 unregister_mods(MOD_BIT(KC_RSFT));
186 }
187 return false;
188 break;
189 }
190 default: {
191 shift_interrupted[0] = true;
192 shift_interrupted[1] = true;
193 break;
194 }
195 }
196
197 return process_action_kb(record);
198}
199
200const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
201 0, 0, 0, 0, 0, 0, 0, 0,
202 0, 0, 0, 0, 0, 0, 0, 0,
203 0, 0, 0, 0, 0, 0, 0, 0,
204 0, 0, 0, 0, 0, 0, 0, 0,
205 0, 1, 1, 1, 1, 1, 1, 0,
206 1, 1, 1, 1, 0, 0, 0, 0,
207 0, 0, 0, 0, 0, 0, 0, 0,
208 0, 0, 1, 0, 1, 0, 1, 1,
209 1, 1, 1, 1, 1, 1, 1, 1,
210 1, 1, 1, 1, 1, 1, 1, 1,
211 1, 1, 1, 1, 1, 1, 1, 1,
212 1, 1, 1, 0, 0, 0, 1, 1,
213 0, 0, 0, 0, 0, 0, 0, 0,
214 0, 0, 0, 0, 0, 0, 0, 0,
215 0, 0, 0, 0, 0, 0, 0, 0,
216 0, 0, 0, 1, 1, 1, 1, 0
217};
218
219const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
220 0, 0, 0, 0, 0, 0, 0, 0,
221 KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
222 0, 0, 0, 0, 0, 0, 0, 0,
223 0, 0, 0, KC_ESC, 0, 0, 0, 0,
224 KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
225 KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
226 KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
227 KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
228 KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
229 KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
230 KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
231 KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
232 KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
233 KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
234 KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
235 KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
236};
237
238/* for users whose OSes are set to Colemak */
239#if 0
240#include "keymap_colemak.h"
241
242const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = {
243 0, 0, 0, 0, 0, 0, 0, 0,
244 0, 0, 0, 0, 0, 0, 0, 0,
245 0, 0, 0, 0, 0, 0, 0, 0,
246 0, 0, 0, 0, 0, 0, 0, 0,
247 0, 1, 1, 1, 1, 1, 1, 0,
248 1, 1, 1, 1, 0, 0, 0, 0,
249 0, 0, 0, 0, 0, 0, 0, 0,
250 0, 0, 1, 0, 1, 0, 1, 1,
251 1, 1, 1, 1, 1, 1, 1, 1,
252 1, 1, 1, 1, 1, 1, 1, 1,
253 1, 1, 1, 1, 1, 1, 1, 1,
254 1, 1, 1, 0, 0, 0, 1, 1,
255 0, 0, 0, 0, 0, 0, 0, 0,
256 0, 0, 0, 0, 0, 0, 0, 0,
257 0, 0, 0, 0, 0, 0, 0, 0,
258 0, 0, 0, 1, 1, 1, 1, 0
259};
260
261const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = {
262 0, 0, 0, 0, 0, 0, 0, 0,
263 KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
264 0, 0, 0, 0, 0, 0, 0, 0,
265 0, 0, 0, KC_ESC, 0, 0, 0, 0,
266 KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
267 KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
268 KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
269 KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
270 KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
271 CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
272 CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
273 CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
274 KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
275 CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
276 CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
277 CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
278};
279
280#endif
281
282void send_string(const char *str) {
283 while (1) {
284 uint8_t keycode;
285 uint8_t ascii_code = pgm_read_byte(str);
286 if (!ascii_code) break;
287 keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]);
288 if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) {
289 register_code(KC_LSFT);
290 register_code(keycode);
291 unregister_code(keycode);
292 unregister_code(KC_LSFT);
293 }
294 else {
295 register_code(keycode);
296 unregister_code(keycode);
297 }
298 ++str;
299 }
300}
301
302void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
303 if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) {
304 layer_on(layer3);
305 } else {
306 layer_off(layer3);
307 }
308}
309
310void tap_random_base64(void) {
311 #if defined(__AVR_ATmega32U4__)
312 uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64;
313 #else
314 uint8_t key = rand() % 64;
315 #endif
316 switch (key) {
317 case 0 ... 25:
318 register_code(KC_LSFT);
319 register_code(key + KC_A);
320 unregister_code(key + KC_A);
321 unregister_code(KC_LSFT);
322 break;
323 case 26 ... 51:
324 register_code(key - 26 + KC_A);
325 unregister_code(key - 26 + KC_A);
326 break;
327 case 52:
328 register_code(KC_0);
329 unregister_code(KC_0);
330 break;
331 case 53 ... 61:
332 register_code(key - 53 + KC_1);
333 unregister_code(key - 53 + KC_1);
334 break;
335 case 62:
336 register_code(KC_LSFT);
337 register_code(KC_EQL);
338 unregister_code(KC_EQL);
339 unregister_code(KC_LSFT);
340 break;
341 case 63:
342 register_code(KC_SLSH);
343 unregister_code(KC_SLSH);
344 break;
345 }
346}
347
348void matrix_init_quantum() {
349 #ifdef BACKLIGHT_ENABLE
350 backlight_init_ports();
351 #endif
352 matrix_init_kb();
353}
354
355void matrix_scan_quantum() {
356 #ifdef AUDIO_ENABLE
357 matrix_scan_music();
358 #endif
359
360 #ifdef TAP_DANCE_ENABLE
361 matrix_scan_tap_dance();
362 #endif
363 matrix_scan_kb();
364}
365
366#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
367
368static const uint8_t backlight_pin = BACKLIGHT_PIN;
369
370#if BACKLIGHT_PIN == B7
371# define COM1x1 COM1C1
372# define OCR1x OCR1C
373#elif BACKLIGHT_PIN == B6
374# define COM1x1 COM1B1
375# define OCR1x OCR1B
376#elif BACKLIGHT_PIN == B5
377# define COM1x1 COM1A1
378# define OCR1x OCR1A
379#else
380# error "Backlight pin not supported - use B5, B6, or B7"
381#endif
382
383__attribute__ ((weak))
384void backlight_init_ports(void)
385{
386
387 // Setup backlight pin as output and output low.
388 // DDRx |= n
389 _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
390 // PORTx &= ~n
391 _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
392
393 // Use full 16-bit resolution.
394 ICR1 = 0xFFFF;
395
396 // I could write a wall of text here to explain... but TL;DW
397 // Go read the ATmega32u4 datasheet.
398 // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
399
400 // Pin PB7 = OCR1C (Timer 1, Channel C)
401 // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
402 // (i.e. start high, go low when counter matches.)
403 // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
404 // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
405
406 TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010;
407 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
408
409 backlight_init();
410 #ifdef BACKLIGHT_BREATHING
411 breathing_defaults();
412 #endif
413}
414
415__attribute__ ((weak))
416void backlight_set(uint8_t level)
417{
418 // Prevent backlight blink on lowest level
419 // PORTx &= ~n
420 _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
421
422 if ( level == 0 ) {
423 // Turn off PWM control on backlight pin, revert to output low.
424 TCCR1A &= ~(_BV(COM1x1));
425 OCR1x = 0x0;
426 } else if ( level == BACKLIGHT_LEVELS ) {
427 // Turn on PWM control of backlight pin
428 TCCR1A |= _BV(COM1x1);
429 // Set the brightness
430 OCR1x = 0xFFFF;
431 } else {
432 // Turn on PWM control of backlight pin
433 TCCR1A |= _BV(COM1x1);
434 // Set the brightness
435 OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
436 }
437
438 #ifdef BACKLIGHT_BREATHING
439 breathing_intensity_default();
440 #endif
441}
442
443
444#ifdef BACKLIGHT_BREATHING
445
446#define BREATHING_NO_HALT 0
447#define BREATHING_HALT_OFF 1
448#define BREATHING_HALT_ON 2
449
450static uint8_t breath_intensity;
451static uint8_t breath_speed;
452static uint16_t breathing_index;
453static uint8_t breathing_halt;
454
455void breathing_enable(void)
456{
457 if (get_backlight_level() == 0)
458 {
459 breathing_index = 0;
460 }
461 else
462 {
463 // Set breathing_index to be at the midpoint (brightest point)
464 breathing_index = 0x20 << breath_speed;
465 }
466
467 breathing_halt = BREATHING_NO_HALT;
468
469 // Enable breathing interrupt
470 TIMSK1 |= _BV(OCIE1A);
471}
472
473void breathing_pulse(void)
474{
475 if (get_backlight_level() == 0)
476 {
477 breathing_index = 0;
478 }
479 else
480 {
481 // Set breathing_index to be at the midpoint + 1 (brightest point)
482 breathing_index = 0x21 << breath_speed;
483 }
484
485 breathing_halt = BREATHING_HALT_ON;
486
487 // Enable breathing interrupt
488 TIMSK1 |= _BV(OCIE1A);
489}
490
491void breathing_disable(void)
492{
493 // Disable breathing interrupt
494 TIMSK1 &= ~_BV(OCIE1A);
495 backlight_set(get_backlight_level());
496}
497
498void breathing_self_disable(void)
499{
500 if (get_backlight_level() == 0)
501 {
502 breathing_halt = BREATHING_HALT_OFF;
503 }
504 else
505 {
506 breathing_halt = BREATHING_HALT_ON;
507 }
508
509 //backlight_set(get_backlight_level());
510}
511
512void breathing_toggle(void)
513{
514 if (!is_breathing())
515 {
516 if (get_backlight_level() == 0)
517 {
518 breathing_index = 0;
519 }
520 else
521 {
522 // Set breathing_index to be at the midpoint + 1 (brightest point)
523 breathing_index = 0x21 << breath_speed;
524 }
525
526 breathing_halt = BREATHING_NO_HALT;
527 }
528
529 // Toggle breathing interrupt
530 TIMSK1 ^= _BV(OCIE1A);
531
532 // Restore backlight level
533 if (!is_breathing())
534 {
535 backlight_set(get_backlight_level());
536 }
537}
538
539bool is_breathing(void)
540{
541 return (TIMSK1 && _BV(OCIE1A));
542}
543
544void breathing_intensity_default(void)
545{
546 //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
547 breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
548}
549
550void breathing_intensity_set(uint8_t value)
551{
552 breath_intensity = value;
553}
554
555void breathing_speed_default(void)
556{
557 breath_speed = 4;
558}
559
560void breathing_speed_set(uint8_t value)
561{
562 bool is_breathing_now = is_breathing();
563 uint8_t old_breath_speed = breath_speed;
564
565 if (is_breathing_now)
566 {
567 // Disable breathing interrupt
568 TIMSK1 &= ~_BV(OCIE1A);
569 }
570
571 breath_speed = value;
572
573 if (is_breathing_now)
574 {
575 // Adjust index to account for new speed
576 breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
577
578 // Enable breathing interrupt
579 TIMSK1 |= _BV(OCIE1A);
580 }
581
582}
583
584void breathing_speed_inc(uint8_t value)
585{
586 if ((uint16_t)(breath_speed - value) > 10 )
587 {
588 breathing_speed_set(0);
589 }
590 else
591 {
592 breathing_speed_set(breath_speed - value);
593 }
594}
595
596void breathing_speed_dec(uint8_t value)
597{
598 if ((uint16_t)(breath_speed + value) > 10 )
599 {
600 breathing_speed_set(10);
601 }
602 else
603 {
604 breathing_speed_set(breath_speed + value);
605 }
606}
607
608void breathing_defaults(void)
609{
610 breathing_intensity_default();
611 breathing_speed_default();
612 breathing_halt = BREATHING_NO_HALT;
613}
614
615/* Breathing Sleep LED brighness(PWM On period) table
616 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
617 *
618 * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
619 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
620 */
621static const uint8_t breathing_table[64] PROGMEM = {
622 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
623 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
624255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
625 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
626};
627
628ISR(TIMER1_COMPA_vect)
629{
630 // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
631
632
633 uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
634
635 if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
636 {
637 // Disable breathing interrupt
638 TIMSK1 &= ~_BV(OCIE1A);
639 }
640
641 OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;
642
643}
644
645
646
647#endif // breathing
648
649#else // backlight
650
651__attribute__ ((weak))
652void backlight_init_ports(void)
653{
654
655}
656
657__attribute__ ((weak))
658void backlight_set(uint8_t level)
659{
660
661}
662
663#endif // backlight
664
665
666
667__attribute__ ((weak))
668void led_set_user(uint8_t usb_led) {
669
670}
671
672__attribute__ ((weak))
673void led_set_kb(uint8_t usb_led) {
674 led_set_user(usb_led);
675}
676
677__attribute__ ((weak))
678void led_init_ports(void)
679{
680
681}
682
683__attribute__ ((weak))
684void led_set(uint8_t usb_led)
685{
686
687 // Example LED Code
688 //
689 // // Using PE6 Caps Lock LED
690 // if (usb_led & (1<<USB_LED_CAPS_LOCK))
691 // {
692 // // Output high.
693 // DDRE |= (1<<6);
694 // PORTE |= (1<<6);
695 // }
696 // else
697 // {
698 // // Output low.
699 // DDRE &= ~(1<<6);
700 // PORTE &= ~(1<<6);
701 // }
702
703 led_set_kb(usb_led);
704}
705
706
707//------------------------------------------------------------------------------
708// Override these functions in your keymap file to play different tunes on
709// different events such as startup and bootloader jump
710
711__attribute__ ((weak))
712void startup_user() {}
713
714__attribute__ ((weak))
715void shutdown_user() {}
716
717//------------------------------------------------------------------------------
diff --git a/quantum/quantum.h b/quantum/quantum.h
new file mode 100644
index 000000000..3a0b74202
--- /dev/null
+++ b/quantum/quantum.h
@@ -0,0 +1,107 @@
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
29
30extern uint32_t default_layer_state;
31
32#ifndef NO_ACTION_LAYER
33 extern uint32_t layer_state;
34#endif
35
36#ifdef MIDI_ENABLE
37 #include <lufa.h>
38 #include "process_midi.h"
39#endif
40
41#ifdef AUDIO_ENABLE
42 #include "audio.h"
43 #include "process_music.h"
44#endif
45
46#ifndef DISABLE_LEADER
47 #include "process_leader.h"
48#endif
49
50#define DISABLE_CHORDING
51#ifndef DISABLE_CHORDING
52 #include "process_chording.h"
53#endif
54
55#ifdef UNICODE_ENABLE
56 #include "process_unicode.h"
57#endif
58
59#include "process_tap_dance.h"
60
61#define SEND_STRING(str) send_string(PSTR(str))
62void send_string(const char *str);
63
64// For tri-layer
65void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
66
67void tap_random_base64(void);
68
69#define IS_LAYER_ON(layer) (layer_state & (1UL << (layer)))
70#define IS_LAYER_OFF(layer) (~layer_state & (1UL << (layer)))
71
72void matrix_init_kb(void);
73void matrix_scan_kb(void);
74void matrix_init_user(void);
75void matrix_scan_user(void);
76bool process_action_kb(keyrecord_t *record);
77bool process_record_kb(uint16_t keycode, keyrecord_t *record);
78bool process_record_user(uint16_t keycode, keyrecord_t *record);
79
80void startup_user(void);
81void shutdown_user(void);
82
83#ifdef BACKLIGHT_ENABLE
84void backlight_init_ports(void);
85
86#ifdef BACKLIGHT_BREATHING
87void breathing_enable(void);
88void breathing_pulse(void);
89void breathing_disable(void);
90void breathing_self_disable(void);
91void breathing_toggle(void);
92bool is_breathing(void);
93
94void breathing_defaults(void);
95void breathing_intensity_default(void);
96void breathing_speed_default(void);
97void breathing_speed_set(uint8_t value);
98void breathing_speed_inc(uint8_t value);
99void breathing_speed_dec(uint8_t value);
100#endif
101
102#endif
103
104void led_set_user(uint8_t usb_led);
105void led_set_kb(uint8_t usb_led);
106
107#endif
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
new file mode 100644
index 000000000..c29ffedc3
--- /dev/null
+++ b/quantum/rgblight.c
@@ -0,0 +1,505 @@
1#include <avr/eeprom.h>
2#include <avr/interrupt.h>
3#include <util/delay.h>
4#include "progmem.h"
5#include "timer.h"
6#include "rgblight.h"
7#include "debug.h"
8
9const uint8_t DIM_CURVE[] PROGMEM = {
10 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
11 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
12 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
13 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
14 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11,
15 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15,
16 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20,
17 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26,
18 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35,
19 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47,
20 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
21 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82,
22 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109,
23 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144,
24 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190,
25 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255,
26};
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};
28const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
29const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
30const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
31const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
32const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20};
33
34rgblight_config_t rgblight_config;
35rgblight_config_t inmem_config;
36struct cRGB led[RGBLED_NUM];
37uint8_t rgblight_inited = 0;
38
39
40void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) {
41 /* convert hue, saturation and brightness ( HSB/HSV ) to RGB
42 The DIM_CURVE is used only on brightness/value and on saturation (inverted).
43 This looks the most natural.
44 */
45 uint8_t r = 0, g = 0, b = 0;
46
47 val = pgm_read_byte(&DIM_CURVE[val]);
48 sat = 255 - pgm_read_byte(&DIM_CURVE[255 - sat]);
49
50 uint8_t base;
51
52 if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
53 r = val;
54 g = val;
55 b = val;
56 } else {
57 base = ((255 - sat) * val) >> 8;
58
59 switch (hue / 60) {
60 case 0:
61 r = val;
62 g = (((val - base)*hue) / 60) + base;
63 b = base;
64 break;
65
66 case 1:
67 r = (((val - base)*(60 - (hue % 60))) / 60) + base;
68 g = val;
69 b = base;
70 break;
71
72 case 2:
73 r = base;
74 g = val;
75 b = (((val - base)*(hue % 60)) / 60) + base;
76 break;
77
78 case 3:
79 r = base;
80 g = (((val - base)*(60 - (hue % 60))) / 60) + base;
81 b = val;
82 break;
83
84 case 4:
85 r = (((val - base)*(hue % 60)) / 60) + base;
86 g = base;
87 b = val;
88 break;
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}
99
100void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) {
101 (*led1).r = r;
102 (*led1).g = g;
103 (*led1).b = b;
104}
105
106
107uint32_t eeconfig_read_rgblight(void) {
108 return eeprom_read_dword(EECONFIG_RGBLIGHT);
109}
110void eeconfig_update_rgblight(uint32_t val) {
111 eeprom_update_dword(EECONFIG_RGBLIGHT, val);
112}
113void eeconfig_update_rgblight_default(void) {
114 dprintf("eeconfig_update_rgblight_default\n");
115 rgblight_config.enable = 1;
116 rgblight_config.mode = 1;
117 rgblight_config.hue = 200;
118 rgblight_config.sat = 204;
119 rgblight_config.val = 204;
120 eeconfig_update_rgblight(rgblight_config.raw);
121}
122void eeconfig_debug_rgblight(void) {
123 dprintf("rgblight_config eprom\n");
124 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
125 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
126 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
127 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
128 dprintf("rgblight_config.val = %d\n", rgblight_config.val);
129}
130
131void rgblight_init(void) {
132 debug_enable = 1; // Debug ON!
133 dprintf("rgblight_init called.\n");
134 rgblight_inited = 1;
135 dprintf("rgblight_init start!\n");
136 if (!eeconfig_is_enabled()) {
137 dprintf("rgblight_init eeconfig is not enabled.\n");
138 eeconfig_init();
139 eeconfig_update_rgblight_default();
140 }
141 rgblight_config.raw = eeconfig_read_rgblight();
142 if (!rgblight_config.mode) {
143 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
144 eeconfig_update_rgblight_default();
145 rgblight_config.raw = eeconfig_read_rgblight();
146 }
147 eeconfig_debug_rgblight(); // display current eeprom values
148
149 rgblight_timer_init(); // setup the timer
150
151 if (rgblight_config.enable) {
152 rgblight_mode(rgblight_config.mode);
153 }
154}
155
156void rgblight_increase(void) {
157 uint8_t mode = 0;
158 if (rgblight_config.mode < RGBLIGHT_MODES) {
159 mode = rgblight_config.mode + 1;
160 }
161 rgblight_mode(mode);
162}
163
164void rgblight_decrease(void) {
165 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.
167 mode = rgblight_config.mode-1;
168 }
169 rgblight_mode(mode);
170}
171
172void rgblight_step(void) {
173 uint8_t mode = 0;
174 mode = rgblight_config.mode + 1;
175 if (mode > RGBLIGHT_MODES) {
176 mode = 1;
177 }
178 rgblight_mode(mode);
179}
180
181void rgblight_mode(uint8_t mode) {
182 if (!rgblight_config.enable) {
183 return;
184 }
185 if (mode<1) {
186 rgblight_config.mode = 1;
187 } else if (mode > RGBLIGHT_MODES) {
188 rgblight_config.mode = RGBLIGHT_MODES;
189 } else {
190 rgblight_config.mode = mode;
191 }
192 eeconfig_update_rgblight(rgblight_config.raw);
193 xprintf("rgblight mode: %u\n", rgblight_config.mode);
194 if (rgblight_config.mode == 1) {
195 rgblight_timer_disable();
196 } else if (rgblight_config.mode >=2 && rgblight_config.mode <=23) {
197 // MODE 2-5, breathing
198 // MODE 6-8, rainbow mood
199 // MODE 9-14, rainbow swirl
200 // MODE 15-20, snake
201 // MODE 21-23, knight
202 rgblight_timer_enable();
203 }
204 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
205}
206
207void rgblight_toggle(void) {
208 rgblight_config.enable ^= 1;
209 eeconfig_update_rgblight(rgblight_config.raw);
210 xprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable);
211 if (rgblight_config.enable) {
212 rgblight_mode(rgblight_config.mode);
213 } else {
214 rgblight_timer_disable();
215 _delay_ms(50);
216 rgblight_set();
217 }
218}
219
220
221void rgblight_increase_hue(void){
222 uint16_t hue;
223 hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360;
224 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
225}
226void rgblight_decrease_hue(void){
227 uint16_t hue;
228 if (rgblight_config.hue-RGBLIGHT_HUE_STEP <0 ) {
229 hue = (rgblight_config.hue+360-RGBLIGHT_HUE_STEP) % 360;
230 } else {
231 hue = (rgblight_config.hue-RGBLIGHT_HUE_STEP) % 360;
232 }
233 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
234}
235void rgblight_increase_sat(void) {
236 uint8_t sat;
237 if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) {
238 sat = 255;
239 } else {
240 sat = rgblight_config.sat+RGBLIGHT_SAT_STEP;
241 }
242 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
243}
244void rgblight_decrease_sat(void){
245 uint8_t sat;
246 if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) {
247 sat = 0;
248 } else {
249 sat = rgblight_config.sat-RGBLIGHT_SAT_STEP;
250 }
251 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
252}
253void rgblight_increase_val(void){
254 uint8_t val;
255 if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) {
256 val = 255;
257 } else {
258 val = rgblight_config.val+RGBLIGHT_VAL_STEP;
259 }
260 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
261}
262void rgblight_decrease_val(void) {
263 uint8_t val;
264 if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) {
265 val = 0;
266 } else {
267 val = rgblight_config.val-RGBLIGHT_VAL_STEP;
268 }
269 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
270}
271
272void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val){
273 inmem_config.raw = rgblight_config.raw;
274 if (rgblight_config.enable) {
275 struct cRGB tmp_led;
276 sethsv(hue, sat, val, &tmp_led);
277 inmem_config.hue = hue;
278 inmem_config.sat = sat;
279 inmem_config.val = val;
280 // 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);
282 }
283}
284void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val){
285 if (rgblight_config.enable) {
286 if (rgblight_config.mode == 1) {
287 // same static color
288 rgblight_sethsv_noeeprom(hue, sat, val);
289 } else {
290 // all LEDs in same color
291 if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
292 // breathing mode, ignore the change of val, use in memory value instead
293 val = rgblight_config.val;
294 } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) {
295 // rainbow mood and rainbow swirl, ignore the change of hue
296 hue = rgblight_config.hue;
297 }
298 }
299 rgblight_config.hue = hue;
300 rgblight_config.sat = sat;
301 rgblight_config.val = val;
302 eeconfig_update_rgblight(rgblight_config.raw);
303 xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
304 }
305}
306
307void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b){
308 // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b);
309 for (uint8_t i=0;i<RGBLED_NUM;i++) {
310 led[i].r = r;
311 led[i].g = g;
312 led[i].b = b;
313 }
314 rgblight_set();
315
316}
317
318void rgblight_set(void) {
319 if (rgblight_config.enable) {
320 ws2812_setleds(led, RGBLED_NUM);
321 } else {
322 for (uint8_t i=0;i<RGBLED_NUM;i++) {
323 led[i].r = 0;
324 led[i].g = 0;
325 led[i].b = 0;
326 }
327 ws2812_setleds(led, RGBLED_NUM);
328 }
329}
330
331// Animation timer -- AVR Timer3
332void rgblight_timer_init(void) {
333 static uint8_t rgblight_timer_is_init = 0;
334 if (rgblight_timer_is_init) {
335 return;
336 }
337 rgblight_timer_is_init = 1;
338 /* Timer 3 setup */
339 TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP
340 | _BV(CS30); //Clock selelct: clk/1
341 /* Set TOP value */
342 uint8_t sreg = SREG;
343 cli();
344 OCR3AH = (RGBLED_TIMER_TOP>>8)&0xff;
345 OCR3AL = RGBLED_TIMER_TOP&0xff;
346 SREG = sreg;
347}
348void rgblight_timer_enable(void) {
349 TIMSK3 |= _BV(OCIE3A);
350 dprintf("TIMER3 enabled.\n");
351}
352void rgblight_timer_disable(void) {
353 TIMSK3 &= ~_BV(OCIE3A);
354 dprintf("TIMER3 disabled.\n");
355}
356void rgblight_timer_toggle(void) {
357 TIMSK3 ^= _BV(OCIE3A);
358 dprintf("TIMER3 toggled.\n");
359}
360
361ISR(TIMER3_COMPA_vect) {
362 // Mode = 1, static light, do nothing here
363 if (rgblight_config.mode>=2 && rgblight_config.mode<=5) {
364 // mode = 2 to 5, breathing mode
365 rgblight_effect_breathing(rgblight_config.mode-2);
366
367 } else if (rgblight_config.mode>=6 && rgblight_config.mode<=8) {
368 rgblight_effect_rainbow_mood(rgblight_config.mode-6);
369 } else if (rgblight_config.mode>=9 && rgblight_config.mode<=14) {
370 rgblight_effect_rainbow_swirl(rgblight_config.mode-9);
371 } else if (rgblight_config.mode>=15 && rgblight_config.mode<=20) {
372 rgblight_effect_snake(rgblight_config.mode-15);
373 } else if (rgblight_config.mode>=21 && rgblight_config.mode<=23) {
374 rgblight_effect_knight(rgblight_config.mode-21);
375 }
376}
377
378// effects
379void rgblight_effect_breathing(uint8_t interval) {
380 static uint8_t pos = 0;
381 static uint16_t last_timer = 0;
382
383 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) return;
384 last_timer = timer_read();
385
386 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos]));
387 pos = (pos+1) % 256;
388}
389
390void rgblight_effect_rainbow_mood(uint8_t interval) {
391 static uint16_t current_hue=0;
392 static uint16_t last_timer = 0;
393
394 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) return;
395 last_timer = timer_read();
396 rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val);
397 current_hue = (current_hue+1) % 360;
398}
399
400void rgblight_effect_rainbow_swirl(uint8_t interval) {
401 static uint16_t current_hue=0;
402 static uint16_t last_timer = 0;
403 uint16_t hue;
404 uint8_t i;
405 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval/2])) return;
406 last_timer = timer_read();
407 for (i=0; i<RGBLED_NUM; i++) {
408 hue = (360/RGBLED_NUM*i+current_hue)%360;
409 sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]);
410 }
411 rgblight_set();
412
413 if (interval % 2) {
414 current_hue = (current_hue+1) % 360;
415 } else {
416 if (current_hue -1 < 0) {
417 current_hue = 359;
418 } else {
419 current_hue = current_hue - 1;
420 }
421
422 }
423}
424void rgblight_effect_snake(uint8_t interval) {
425 static uint8_t pos=0;
426 static uint16_t last_timer = 0;
427 uint8_t i,j;
428 int8_t k;
429 int8_t increament = 1;
430 if (interval%2) increament = -1;
431 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval/2])) return;
432 last_timer = timer_read();
433 for (i=0;i<RGBLED_NUM;i++) {
434 led[i].r=0;
435 led[i].g=0;
436 led[i].b=0;
437 for (j=0;j<RGBLIGHT_EFFECT_SNAKE_LENGTH;j++) {
438 k = pos+j*increament;
439 if (k<0) k = k+RGBLED_NUM;
440 if (i==k) {
441 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]);
442 }
443 }
444 }
445 rgblight_set();
446 if (increament == 1) {
447 if (pos - 1 < 0) {
448 pos = RGBLED_NUM-1;
449 } else {
450 pos -= 1;
451 }
452 } else {
453 pos = (pos+1)%RGBLED_NUM;
454 }
455
456}
457
458void rgblight_effect_knight(uint8_t interval) {
459 static int8_t pos=0;
460 static uint16_t last_timer = 0;
461 uint8_t i,j,cur;
462 int8_t k;
463 struct cRGB preled[RGBLED_NUM];
464 static int8_t increament = -1;
465 if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) return;
466 last_timer = timer_read();
467 for (i=0;i<RGBLED_NUM;i++) {
468 preled[i].r=0;
469 preled[i].g=0;
470 preled[i].b=0;
471 for (j=0;j<RGBLIGHT_EFFECT_KNIGHT_LENGTH;j++) {
472 k = pos+j*increament;
473 if (k<0) k = 0;
474 if (k>=RGBLED_NUM) k=RGBLED_NUM-1;
475 if (i==k) {
476 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]);
477 }
478 }
479 }
480 if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) {
481 for (i=0;i<RGBLED_NUM;i++) {
482 cur = (i+RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM;
483 led[i].r = preled[cur].r;
484 led[i].g = preled[cur].g;
485 led[i].b = preled[cur].b;
486 }
487 }
488 rgblight_set();
489 if (increament == 1) {
490 if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) {
491 pos = 0- RGBLIGHT_EFFECT_KNIGHT_LENGTH;
492 increament = -1;
493 } else {
494 pos -= 1;
495 }
496 } else {
497 if (pos+1>RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH) {
498 pos = RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH-1;
499 increament = 1;
500 } else {
501 pos += 1;
502 }
503 }
504
505}
diff --git a/quantum/rgblight.h b/quantum/rgblight.h
new file mode 100644
index 000000000..64f92523e
--- /dev/null
+++ b/quantum/rgblight.h
@@ -0,0 +1,86 @@
1#ifndef RGBLIGHT_H
2#define RGBLIGHT_H
3
4#ifndef RGBLIGHT_MODES
5#define RGBLIGHT_MODES 23
6#endif
7
8#ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH
9#define RGBLIGHT_EFFECT_SNAKE_LENGTH 7
10#endif
11
12#ifndef RGBLIGHT_EFFECT_KNIGHT_LENGTH
13#define RGBLIGHT_EFFECT_KNIGHT_LENGTH 7
14#endif
15#ifndef RGBLIGHT_EFFECT_KNIGHT_OFFSET
16#define RGBLIGHT_EFFECT_KNIGHT_OFFSET 9
17#endif
18
19#ifndef RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH
20#define RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH 4
21#endif
22
23#ifndef RGBLIGHT_HUE_STEP
24#define RGBLIGHT_HUE_STEP 10
25#endif
26#ifndef RGBLIGHT_SAT_STEP
27#define RGBLIGHT_SAT_STEP 17
28#endif
29#ifndef RGBLIGHT_VAL_STEP
30#define RGBLIGHT_VAL_STEP 17
31#endif
32
33#define RGBLED_TIMER_TOP F_CPU/(256*64)
34
35#include <stdint.h>
36#include <stdbool.h>
37#include "eeconfig.h"
38#include "light_ws2812.h"
39
40typedef union {
41 uint32_t raw;
42 struct {
43 bool enable :1;
44 uint8_t mode :6;
45 uint16_t hue :9;
46 uint8_t sat :8;
47 uint8_t val :8;
48 };
49} rgblight_config_t;
50
51void rgblight_init(void);
52void rgblight_increase(void);
53void rgblight_decrease(void);
54void rgblight_toggle(void);
55void rgblight_step(void);
56void rgblight_mode(uint8_t mode);
57void rgblight_set(void);
58void rgblight_increase_hue(void);
59void rgblight_decrease_hue(void);
60void rgblight_increase_sat(void);
61void rgblight_decrease_sat(void);
62void rgblight_increase_val(void);
63void rgblight_decrease_val(void);
64void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val);
65void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b);
66
67uint32_t eeconfig_read_rgblight(void);
68void eeconfig_update_rgblight(uint32_t val);
69void eeconfig_update_rgblight_default(void);
70void eeconfig_debug_rgblight(void);
71
72void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1);
73void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1);
74void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val);
75
76void rgblight_timer_init(void);
77void rgblight_timer_enable(void);
78void rgblight_timer_disable(void);
79void rgblight_timer_toggle(void);
80void rgblight_effect_breathing(uint8_t interval);
81void rgblight_effect_rainbow_mood(uint8_t interval);
82void rgblight_effect_rainbow_swirl(uint8_t interval);
83void rgblight_effect_snake(uint8_t interval);
84void rgblight_effect_knight(uint8_t interval);
85
86#endif
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..fb4c45a8d
--- /dev/null
+++ b/quantum/serial_link/protocol/byte_stuffer.c
@@ -0,0 +1,145 @@
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
34#define MAX_FRAME_SIZE 1024
35#define NUM_LINKS 2
36
37typedef struct byte_stuffer_state {
38 uint16_t next_zero;
39 uint16_t data_pos;
40 bool long_frame;
41 uint8_t data[MAX_FRAME_SIZE];
42}byte_stuffer_state_t;
43
44static byte_stuffer_state_t states[NUM_LINKS];
45
46void init_byte_stuffer_state(byte_stuffer_state_t* state) {
47 state->next_zero = 0;
48 state->data_pos = 0;
49 state->long_frame = false;
50}
51
52void init_byte_stuffer(void) {
53 int i;
54 for (i=0;i<NUM_LINKS;i++) {
55 init_byte_stuffer_state(&states[i]);
56 }
57}
58
59void byte_stuffer_recv_byte(uint8_t link, uint8_t data) {
60 byte_stuffer_state_t* state = &states[link];
61 // Start of a new frame
62 if (state->next_zero == 0) {
63 state->next_zero = data;
64 state->long_frame = data == 0xFF;
65 state->data_pos = 0;
66 return;
67 }
68
69 state->next_zero--;
70 if (data == 0) {
71 if (state->next_zero == 0) {
72 // The frame is completed
73 if (state->data_pos > 0) {
74 validator_recv_frame(link, state->data, state->data_pos);
75 }
76 }
77 else {
78 // The frame is invalid, so reset
79 init_byte_stuffer_state(state);
80 }
81 }
82 else {
83 if (state->data_pos == MAX_FRAME_SIZE) {
84 // We exceeded our maximum frame size
85 // therefore there's nothing else to do than reset to a new frame
86 state->next_zero = data;
87 state->long_frame = data == 0xFF;
88 state->data_pos = 0;
89 }
90 else if (state->next_zero == 0) {
91 if (state->long_frame) {
92 // This is part of a long frame, so continue
93 state->next_zero = data;
94 state->long_frame = data == 0xFF;
95 }
96 else {
97 // Special case for zeroes
98 state->next_zero = data;
99 state->data[state->data_pos++] = 0;
100 }
101 }
102 else {
103 state->data[state->data_pos++] = data;
104 }
105 }
106}
107
108static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) {
109 send_data(link, &num_non_zero, 1);
110 if (end > start) {
111 send_data(link, start, end-start);
112 }
113}
114
115void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
116 const uint8_t zero = 0;
117 if (size > 0) {
118 uint16_t num_non_zero = 1;
119 uint8_t* end = data + size;
120 uint8_t* start = data;
121 while (data < end) {
122 if (num_non_zero == 0xFF) {
123 // There's more data after big non-zero block
124 // So send it, and start a new block
125 send_block(link, start, data, num_non_zero);
126 start = data;
127 num_non_zero = 1;
128 }
129 else {
130 if (*data == 0) {
131 // A zero encountered, so send the block
132 send_block(link, start, data, num_non_zero);
133 start = data + 1;
134 num_non_zero = 1;
135 }
136 else {
137 num_non_zero++;
138 }
139 ++data;
140 }
141 }
142 send_block(link, start, data, num_non_zero);
143 send_data(link, &zero, 1);
144 }
145}
diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h
new file mode 100644
index 000000000..2cc88beb4
--- /dev/null
+++ b/quantum/serial_link/protocol/byte_stuffer.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_BYTE_STUFFER_H
26#define SERIAL_LINK_BYTE_STUFFER_H
27
28#include <stdint.h>
29
30void init_byte_stuffer(void);
31void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
32void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);
33
34#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..f418d11ce
--- /dev/null
+++ b/quantum/serial_link/protocol/transport.c
@@ -0,0 +1,124 @@
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 add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
35 unsigned int i;
36 for(i=0;i<_num_remote_objects;i++) {
37 remote_object_t* obj = _remote_objects[i];
38 remote_objects[num_remote_objects++] = obj;
39 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
40 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
41 triple_buffer_init(tb);
42 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
43 tb = (triple_buffer_object_t*)start;
44 triple_buffer_init(tb);
45 }
46 else if(obj->object_type == MASTER_TO_SINGLE_SLAVE) {
47 uint8_t* start = obj->buffer;
48 unsigned int j;
49 for (j=0;j<NUM_SLAVES;j++) {
50 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
51 triple_buffer_init(tb);
52 start += LOCAL_OBJECT_SIZE(obj->object_size);
53 }
54 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
55 triple_buffer_init(tb);
56 }
57 else {
58 uint8_t* start = obj->buffer;
59 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
60 triple_buffer_init(tb);
61 start += LOCAL_OBJECT_SIZE(obj->object_size);
62 unsigned int j;
63 for (j=0;j<NUM_SLAVES;j++) {
64 tb = (triple_buffer_object_t*)start;
65 triple_buffer_init(tb);
66 start += REMOTE_OBJECT_SIZE(obj->object_size);
67 }
68 }
69 }
70}
71
72void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
73 uint8_t id = data[size-1];
74 if (id < num_remote_objects) {
75 remote_object_t* obj = remote_objects[id];
76 if (obj->object_size == size - 1) {
77 uint8_t* start;
78 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
79 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
80 }
81 else if(obj->object_type == SLAVE_TO_MASTER) {
82 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
83 start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size);
84 }
85 else {
86 start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);
87 }
88 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
89 void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb);
90 memcpy(ptr, data, size - 1);
91 triple_buffer_end_write_internal(tb);
92 }
93 }
94}
95
96void update_transport(void) {
97 unsigned int i;
98 for(i=0;i<num_remote_objects;i++) {
99 remote_object_t* obj = remote_objects[i];
100 if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) {
101 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
102 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
103 if (ptr) {
104 ptr[obj->object_size] = i;
105 uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0;
106 router_send_frame(dest, ptr, obj->object_size + 1);
107 }
108 }
109 else {
110 uint8_t* start = obj->buffer;
111 unsigned int j;
112 for (j=0;j<NUM_SLAVES;j++) {
113 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
114 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
115 if (ptr) {
116 ptr[obj->object_size] = i;
117 uint8_t dest = j + 1;
118 router_send_frame(dest, ptr, obj->object_size + 1);
119 }
120 start += LOCAL_OBJECT_SIZE(obj->object_size);
121 }
122 }
123 }
124}
diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h
new file mode 100644
index 000000000..9a052d880
--- /dev/null
+++ b/quantum/serial_link/protocol/transport.h
@@ -0,0 +1,151 @@
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 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 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 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 transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
149void update_transport(void);
150
151#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.c b/quantum/serial_link/tests/byte_stuffer_tests.c
new file mode 100644
index 000000000..64b170e8c
--- /dev/null
+++ b/quantum/serial_link/tests/byte_stuffer_tests.c
@@ -0,0 +1,506 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/byte_stuffer.h"
28#include "serial_link/protocol/byte_stuffer.c"
29#include "serial_link/protocol/frame_validator.h"
30#include "serial_link/protocol/physical.h"
31
32static uint8_t sent_data[MAX_FRAME_SIZE*2];
33static uint16_t sent_data_size;
34
35Describe(ByteStuffer);
36BeforeEach(ByteStuffer) {
37 init_byte_stuffer();
38 sent_data_size = 0;
39}
40AfterEach(ByteStuffer) {}
41
42void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
43 mock(data, size);
44}
45
46void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
47 memcpy(sent_data + sent_data_size, data, size);
48 sent_data_size += size;
49}
50
51Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
52 never_expect(validator_recv_frame);
53 byte_stuffer_recv_byte(0, 0);
54}
55
56Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
57 never_expect(validator_recv_frame);
58 byte_stuffer_recv_byte(0, 0xFF);
59}
60
61Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
62 never_expect(validator_recv_frame);
63 byte_stuffer_recv_byte(0, 0x4A);
64}
65
66Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
67 never_expect(validator_recv_frame);
68 byte_stuffer_recv_byte(0, 1);
69 byte_stuffer_recv_byte(0, 0);
70}
71
72Ensure(ByteStuffer, receives_single_byte_valid_frame) {
73 uint8_t expected[] = {0x37};
74 expect(validator_recv_frame,
75 when(size, is_equal_to(1)),
76 when(data, is_equal_to_contents_of(expected, 1))
77 );
78 byte_stuffer_recv_byte(0, 2);
79 byte_stuffer_recv_byte(0, 0x37);
80 byte_stuffer_recv_byte(0, 0);
81}
82
83Ensure(ByteStuffer, receives_three_bytes_valid_frame) {
84 uint8_t expected[] = {0x37, 0x99, 0xFF};
85 expect(validator_recv_frame,
86 when(size, is_equal_to(3)),
87 when(data, is_equal_to_contents_of(expected, 3))
88 );
89 byte_stuffer_recv_byte(0, 4);
90 byte_stuffer_recv_byte(0, 0x37);
91 byte_stuffer_recv_byte(0, 0x99);
92 byte_stuffer_recv_byte(0, 0xFF);
93 byte_stuffer_recv_byte(0, 0);
94}
95
96Ensure(ByteStuffer, receives_single_zero_valid_frame) {
97 uint8_t expected[] = {0};
98 expect(validator_recv_frame,
99 when(size, is_equal_to(1)),
100 when(data, is_equal_to_contents_of(expected, 1))
101 );
102 byte_stuffer_recv_byte(0, 1);
103 byte_stuffer_recv_byte(0, 1);
104 byte_stuffer_recv_byte(0, 0);
105}
106
107Ensure(ByteStuffer, receives_valid_frame_with_zeroes) {
108 uint8_t expected[] = {5, 0, 3, 0};
109 expect(validator_recv_frame,
110 when(size, is_equal_to(4)),
111 when(data, is_equal_to_contents_of(expected, 4))
112 );
113 byte_stuffer_recv_byte(0, 2);
114 byte_stuffer_recv_byte(0, 5);
115 byte_stuffer_recv_byte(0, 2);
116 byte_stuffer_recv_byte(0, 3);
117 byte_stuffer_recv_byte(0, 1);
118 byte_stuffer_recv_byte(0, 0);
119}
120
121Ensure(ByteStuffer, receives_two_valid_frames) {
122 uint8_t expected1[] = {5, 0};
123 uint8_t expected2[] = {3};
124 expect(validator_recv_frame,
125 when(size, is_equal_to(2)),
126 when(data, is_equal_to_contents_of(expected1, 2))
127 );
128 expect(validator_recv_frame,
129 when(size, is_equal_to(1)),
130 when(data, is_equal_to_contents_of(expected2, 1))
131 );
132 byte_stuffer_recv_byte(1, 2);
133 byte_stuffer_recv_byte(1, 5);
134 byte_stuffer_recv_byte(1, 1);
135 byte_stuffer_recv_byte(1, 0);
136 byte_stuffer_recv_byte(1, 2);
137 byte_stuffer_recv_byte(1, 3);
138 byte_stuffer_recv_byte(1, 0);
139}
140
141Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
142 uint8_t expected[] = {5, 7};
143 expect(validator_recv_frame,
144 when(size, is_equal_to(2)),
145 when(data, is_equal_to_contents_of(expected, 2))
146 );
147 byte_stuffer_recv_byte(1, 3);
148 byte_stuffer_recv_byte(1, 1);
149 byte_stuffer_recv_byte(1, 0);
150 byte_stuffer_recv_byte(1, 3);
151 byte_stuffer_recv_byte(1, 5);
152 byte_stuffer_recv_byte(1, 7);
153 byte_stuffer_recv_byte(1, 0);
154}
155
156Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
157 uint8_t expected[] = {5, 7};
158 expect(validator_recv_frame,
159 when(size, is_equal_to(2)),
160 when(data, is_equal_to_contents_of(expected, 2))
161 );
162 byte_stuffer_recv_byte(0, 2);
163 byte_stuffer_recv_byte(0, 9);
164 byte_stuffer_recv_byte(0, 4); // This should have been zero
165 byte_stuffer_recv_byte(0, 0);
166 byte_stuffer_recv_byte(0, 3);
167 byte_stuffer_recv_byte(0, 5);
168 byte_stuffer_recv_byte(0, 7);
169 byte_stuffer_recv_byte(0, 0);
170}
171
172Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
173 uint8_t expected[254];
174 int i;
175 for (i=0;i<254;i++) {
176 expected[i] = i + 1;
177 }
178 expect(validator_recv_frame,
179 when(size, is_equal_to(254)),
180 when(data, is_equal_to_contents_of(expected, 254))
181 );
182 byte_stuffer_recv_byte(0, 0xFF);
183 for (i=0;i<254;i++) {
184 byte_stuffer_recv_byte(0, i+1);
185 }
186 byte_stuffer_recv_byte(0, 0);
187}
188
189Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
190 uint8_t expected[255];
191 int i;
192 for (i=0;i<254;i++) {
193 expected[i] = i + 1;
194 }
195 expected[254] = 7;
196 expect(validator_recv_frame,
197 when(size, is_equal_to(255)),
198 when(data, is_equal_to_contents_of(expected, 255))
199 );
200 byte_stuffer_recv_byte(0, 0xFF);
201 for (i=0;i<254;i++) {
202 byte_stuffer_recv_byte(0, i+1);
203 }
204 byte_stuffer_recv_byte(0, 2);
205 byte_stuffer_recv_byte(0, 7);
206 byte_stuffer_recv_byte(0, 0);
207}
208
209Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
210 uint8_t expected[255];
211 int i;
212 for (i=0;i<254;i++) {
213 expected[i] = i + 1;
214 }
215 expected[254] = 0;
216 expect(validator_recv_frame,
217 when(size, is_equal_to(255)),
218 when(data, is_equal_to_contents_of(expected, 255))
219 );
220 byte_stuffer_recv_byte(0, 0xFF);
221 for (i=0;i<254;i++) {
222 byte_stuffer_recv_byte(0, i+1);
223 }
224 byte_stuffer_recv_byte(0, 1);
225 byte_stuffer_recv_byte(0, 1);
226 byte_stuffer_recv_byte(0, 0);
227}
228
229Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
230 uint8_t expected[515];
231 int i;
232 int j;
233 for (j=0;j<2;j++) {
234 for (i=0;i<254;i++) {
235 expected[i+254*j] = i + 1;
236 }
237 }
238 for (i=0;i<7;i++) {
239 expected[254*2+i] = i + 1;
240 }
241 expect(validator_recv_frame,
242 when(size, is_equal_to(515)),
243 when(data, is_equal_to_contents_of(expected, 510))
244 );
245 byte_stuffer_recv_byte(0, 0xFF);
246 for (i=0;i<254;i++) {
247 byte_stuffer_recv_byte(0, i+1);
248 }
249 byte_stuffer_recv_byte(0, 0xFF);
250 for (i=0;i<254;i++) {
251 byte_stuffer_recv_byte(0, i+1);
252 }
253 byte_stuffer_recv_byte(0, 8);
254 byte_stuffer_recv_byte(0, 1);
255 byte_stuffer_recv_byte(0, 2);
256 byte_stuffer_recv_byte(0, 3);
257 byte_stuffer_recv_byte(0, 4);
258 byte_stuffer_recv_byte(0, 5);
259 byte_stuffer_recv_byte(0, 6);
260 byte_stuffer_recv_byte(0, 7);
261 byte_stuffer_recv_byte(0, 0);
262}
263
264Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
265 uint8_t expected[MAX_FRAME_SIZE] = {};
266 expect(validator_recv_frame,
267 when(size, is_equal_to(MAX_FRAME_SIZE)),
268 when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE))
269 );
270 int i;
271 byte_stuffer_recv_byte(0, 1);
272 for(i=0;i<MAX_FRAME_SIZE;i++) {
273 byte_stuffer_recv_byte(0, 1);
274 }
275 byte_stuffer_recv_byte(0, 0);
276}
277
278Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
279 uint8_t expected[1] = {0};
280 never_expect(validator_recv_frame);
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
290Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
291 uint8_t expected[1] = {1};
292 expect(validator_recv_frame,
293 when(size, is_equal_to(1)),
294 when(data, is_equal_to_contents_of(expected, 1))
295 );
296 int i;
297 byte_stuffer_recv_byte(0, 1);
298 for(i=0;i<MAX_FRAME_SIZE;i++) {
299 byte_stuffer_recv_byte(0, 1);
300 }
301 byte_stuffer_recv_byte(0, 2);
302 byte_stuffer_recv_byte(0, 1);
303 byte_stuffer_recv_byte(0, 0);
304}
305
306Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
307 assert_that(sent_data_size, is_equal_to(0));
308 byte_stuffer_send_frame(0, NULL, 0);
309}
310
311Ensure(ByteStuffer, send_one_byte_frame) {
312 uint8_t data[] = {5};
313 byte_stuffer_send_frame(1, data, 1);
314 uint8_t expected[] = {2, 5, 0};
315 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
316 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
317}
318
319Ensure(ByteStuffer, sends_two_byte_frame) {
320 uint8_t data[] = {5, 0x77};
321 byte_stuffer_send_frame(0, data, 2);
322 uint8_t expected[] = {3, 5, 0x77, 0};
323 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
324 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
325}
326
327Ensure(ByteStuffer, sends_one_byte_frame_with_zero) {
328 uint8_t data[] = {0};
329 byte_stuffer_send_frame(0, data, 1);
330 uint8_t expected[] = {1, 1, 0};
331 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
332 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
333}
334
335Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
336 uint8_t data[] = {0, 9};
337 byte_stuffer_send_frame(1, data, 2);
338 uint8_t expected[] = {1, 2, 9, 0};
339 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
340 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
341}
342
343Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
344 uint8_t data[] = {9, 0};
345 byte_stuffer_send_frame(1, data, 2);
346 uint8_t expected[] = {2, 9, 1, 0};
347 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
348 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
349}
350
351Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
352 uint8_t data[] = {9, 0, 0x68};
353 byte_stuffer_send_frame(0, data, 3);
354 uint8_t expected[] = {2, 9, 2, 0x68, 0};
355 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
356 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
357}
358
359Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
360 uint8_t data[] = {0, 0x55, 0};
361 byte_stuffer_send_frame(0, data, 3);
362 uint8_t expected[] = {1, 2, 0x55, 1, 0};
363 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
364 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
365}
366
367Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
368 uint8_t data[] = {0, 0, 0};
369 byte_stuffer_send_frame(0, data, 3);
370 uint8_t expected[] = {1, 1, 1, 1, 0};
371 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
372 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
373}
374
375Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) {
376 uint8_t data[254];
377 int i;
378 for(i=0;i<254;i++) {
379 data[i] = i + 1;
380 }
381 byte_stuffer_send_frame(0, data, 254);
382 uint8_t expected[256];
383 expected[0] = 0xFF;
384 for(i=1;i<255;i++) {
385 expected[i] = i;
386 }
387 expected[255] = 0;
388 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
389 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
390}
391
392Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) {
393 uint8_t data[255];
394 int i;
395 for(i=0;i<255;i++) {
396 data[i] = i + 1;
397 }
398 byte_stuffer_send_frame(0, data, 255);
399 uint8_t expected[258];
400 expected[0] = 0xFF;
401 for(i=1;i<255;i++) {
402 expected[i] = i;
403 }
404 expected[255] = 2;
405 expected[256] = 255;
406 expected[257] = 0;
407 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
408 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
409}
410
411Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
412 uint8_t data[255];
413 int i;
414 for(i=0;i<254;i++) {
415 data[i] = i + 1;
416 }
417 data[255] = 0;
418 byte_stuffer_send_frame(0, data, 255);
419 uint8_t expected[258];
420 expected[0] = 0xFF;
421 for(i=1;i<255;i++) {
422 expected[i] = i;
423 }
424 expected[255] = 1;
425 expected[256] = 1;
426 expected[257] = 0;
427 assert_that(sent_data_size, is_equal_to(sizeof(expected)));
428 assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
429}
430
431Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
432 uint8_t original_data[] = { 1, 2, 3};
433 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
434 expect(validator_recv_frame,
435 when(size, is_equal_to(sizeof(original_data))),
436 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
437 );
438 int i;
439 for(i=0;i<sent_data_size;i++) {
440 byte_stuffer_recv_byte(1, sent_data[i]);
441 }
442}
443
444Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
445 uint8_t original_data[] = { 1, 0, 3, 0, 0, 9};
446 byte_stuffer_send_frame(1, original_data, sizeof(original_data));
447 expect(validator_recv_frame,
448 when(size, is_equal_to(sizeof(original_data))),
449 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
450 );
451 int i;
452 for(i=0;i<sent_data_size;i++) {
453 byte_stuffer_recv_byte(0, sent_data[i]);
454 }
455}
456
457Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
458 uint8_t original_data[254];
459 int i;
460 for(i=0;i<254;i++) {
461 original_data[i] = i + 1;
462 }
463 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
464 expect(validator_recv_frame,
465 when(size, is_equal_to(sizeof(original_data))),
466 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
467 );
468 for(i=0;i<sent_data_size;i++) {
469 byte_stuffer_recv_byte(1, sent_data[i]);
470 }
471}
472
473Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
474 uint8_t original_data[256];
475 int i;
476 for(i=0;i<254;i++) {
477 original_data[i] = i + 1;
478 }
479 original_data[254] = 22;
480 original_data[255] = 23;
481 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
482 expect(validator_recv_frame,
483 when(size, is_equal_to(sizeof(original_data))),
484 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
485 );
486 for(i=0;i<sent_data_size;i++) {
487 byte_stuffer_recv_byte(1, sent_data[i]);
488 }
489}
490
491Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
492 uint8_t original_data[255];
493 int i;
494 for(i=0;i<254;i++) {
495 original_data[i] = i + 1;
496 }
497 original_data[254] = 0;
498 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
499 expect(validator_recv_frame,
500 when(size, is_equal_to(sizeof(original_data))),
501 when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
502 );
503 for(i=0;i<sent_data_size;i++) {
504 byte_stuffer_recv_byte(1, sent_data[i]);
505 }
506}
diff --git a/quantum/serial_link/tests/frame_router_tests.c b/quantum/serial_link/tests/frame_router_tests.c
new file mode 100644
index 000000000..6c806fa93
--- /dev/null
+++ b/quantum/serial_link/tests/frame_router_tests.c
@@ -0,0 +1,231 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/byte_stuffer.c"
28#include "serial_link/protocol/frame_validator.c"
29#include "serial_link/protocol/frame_router.c"
30#include "serial_link/protocol/transport.h"
31
32static uint8_t received_data[256];
33static uint16_t received_data_size;
34
35typedef struct {
36 uint8_t sent_data[256];
37 uint16_t sent_data_size;
38} receive_buffer_t;
39
40typedef struct {
41 receive_buffer_t send_buffers[2];
42} router_buffer_t;
43
44router_buffer_t router_buffers[8];
45
46router_buffer_t* current_router_buffer;
47
48
49Describe(FrameRouter);
50BeforeEach(FrameRouter) {
51 init_byte_stuffer();
52 memset(router_buffers, 0, sizeof(router_buffers));
53 current_router_buffer = 0;
54}
55AfterEach(FrameRouter) {}
56
57typedef struct {
58 uint32_t data;
59 uint8_t extra[16];
60} frame_buffer_t;
61
62
63void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
64 receive_buffer_t* buffer = &current_router_buffer->send_buffers[link];
65 memcpy(buffer->sent_data + buffer->sent_data_size, data, size);
66 buffer->sent_data_size += size;
67}
68
69static void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
70 int i;
71 for(i=0;i<size;i++) {
72 byte_stuffer_recv_byte(link, data[i]);
73 }
74}
75
76static void activate_router(uint8_t num) {
77 current_router_buffer = router_buffers + num;
78 router_set_master(num==0);
79}
80
81static void simulate_transport(uint8_t from, uint8_t to) {
82 activate_router(to);
83 if (from > to) {
84 receive_data(DOWN_LINK,
85 router_buffers[from].send_buffers[UP_LINK].sent_data,
86 router_buffers[from].send_buffers[UP_LINK].sent_data_size);
87 }
88 else if(to > from) {
89 receive_data(UP_LINK,
90 router_buffers[from].send_buffers[DOWN_LINK].sent_data,
91 router_buffers[from].send_buffers[DOWN_LINK].sent_data_size);
92 }
93}
94
95void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
96 mock(from, data, size);
97}
98
99
100Ensure(FrameRouter, master_broadcast_is_received_by_everyone) {
101 frame_buffer_t data;
102 data.data = 0xAB7055BB;
103 activate_router(0);
104 router_send_frame(0xFF, (uint8_t*)&data, 4);
105 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
106 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
107
108 expect(transport_recv_frame,
109 when(from, is_equal_to(0)),
110 when(size, is_equal_to(4)),
111 when(data, is_equal_to_contents_of(&data.data, 4))
112 );
113 simulate_transport(0, 1);
114 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
115 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
116
117 expect(transport_recv_frame,
118 when(from, is_equal_to(0)),
119 when(size, is_equal_to(4)),
120 when(data, is_equal_to_contents_of(&data.data, 4))
121 );
122 simulate_transport(1, 2);
123 assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
124 assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
125}
126
127Ensure(FrameRouter, master_send_is_received_by_targets) {
128 frame_buffer_t data;
129 data.data = 0xAB7055BB;
130 activate_router(0);
131 router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
132 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
133 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
134
135 simulate_transport(0, 1);
136 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
137 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
138
139 expect(transport_recv_frame,
140 when(from, is_equal_to(0)),
141 when(size, is_equal_to(4)),
142 when(data, is_equal_to_contents_of(&data.data, 4))
143 );
144 simulate_transport(1, 2);
145 assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
146 assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
147
148 expect(transport_recv_frame,
149 when(from, is_equal_to(0)),
150 when(size, is_equal_to(4)),
151 when(data, is_equal_to_contents_of(&data.data, 4))
152 );
153 simulate_transport(2, 3);
154 assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
155 assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
156}
157
158Ensure(FrameRouter, first_link_sends_to_master) {
159 frame_buffer_t data;
160 data.data = 0xAB7055BB;
161 activate_router(1);
162 router_send_frame(0, (uint8_t*)&data, 4);
163 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
164 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
165
166 expect(transport_recv_frame,
167 when(from, is_equal_to(1)),
168 when(size, is_equal_to(4)),
169 when(data, is_equal_to_contents_of(&data.data, 4))
170 );
171 simulate_transport(1, 0);
172 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
173 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
174}
175
176Ensure(FrameRouter, second_link_sends_to_master) {
177 frame_buffer_t data;
178 data.data = 0xAB7055BB;
179 activate_router(2);
180 router_send_frame(0, (uint8_t*)&data, 4);
181 assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
182 assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
183
184 simulate_transport(2, 1);
185 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
186 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
187
188 expect(transport_recv_frame,
189 when(from, is_equal_to(2)),
190 when(size, is_equal_to(4)),
191 when(data, is_equal_to_contents_of(&data.data, 4))
192 );
193 simulate_transport(1, 0);
194 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
195 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
196}
197
198Ensure(FrameRouter, master_sends_to_master_does_nothing) {
199 frame_buffer_t data;
200 data.data = 0xAB7055BB;
201 activate_router(0);
202 router_send_frame(0, (uint8_t*)&data, 4);
203 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
204 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
205}
206
207Ensure(FrameRouter, link_sends_to_other_link_does_nothing) {
208 frame_buffer_t data;
209 data.data = 0xAB7055BB;
210 activate_router(1);
211 router_send_frame(2, (uint8_t*)&data, 4);
212 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
213 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
214}
215
216Ensure(FrameRouter, master_receives_on_uplink_does_nothing) {
217 frame_buffer_t data;
218 data.data = 0xAB7055BB;
219 activate_router(1);
220 router_send_frame(0, (uint8_t*)&data, 4);
221 assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
222 assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
223
224 never_expect(transport_recv_frame);
225 activate_router(0);
226 receive_data(UP_LINK,
227 router_buffers[1].send_buffers[UP_LINK].sent_data,
228 router_buffers[1].send_buffers[UP_LINK].sent_data_size);
229 assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
230 assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
231}
diff --git a/quantum/serial_link/tests/frame_validator_tests.c b/quantum/serial_link/tests/frame_validator_tests.c
new file mode 100644
index 000000000..d20947e2c
--- /dev/null
+++ b/quantum/serial_link/tests/frame_validator_tests.c
@@ -0,0 +1,101 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/frame_validator.c"
28
29void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
30 mock(data, size);
31}
32
33void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
34 mock(data, size);
35}
36
37Describe(FrameValidator);
38BeforeEach(FrameValidator) {}
39AfterEach(FrameValidator) {}
40
41Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) {
42 never_expect(route_incoming_frame);
43 uint8_t data[] = {1, 2};
44 validator_recv_frame(0, 0, 1);
45 validator_recv_frame(0, data, 2);
46 validator_recv_frame(0, data, 3);
47 validator_recv_frame(0, data, 4);
48}
49
50Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) {
51 uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
52 expect(route_incoming_frame,
53 when(size, is_equal_to(1)),
54 when(data, is_equal_to_contents_of(data, 1))
55 );
56 validator_recv_frame(0, data, 5);
57}
58
59Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
60 uint8_t data[] = {0x44, 0, 0, 0, 0};
61 never_expect(route_incoming_frame);
62 validator_recv_frame(1, data, 5);
63}
64
65Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) {
66 uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
67 expect(route_incoming_frame,
68 when(size, is_equal_to(4)),
69 when(data, is_equal_to_contents_of(data, 4))
70 );
71 validator_recv_frame(1, data, 8);
72}
73
74Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) {
75 uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
76 expect(route_incoming_frame,
77 when(size, is_equal_to(5)),
78 when(data, is_equal_to_contents_of(data, 5))
79 );
80 validator_recv_frame(0, data, 9);
81}
82
83Ensure(FrameValidator, sends_one_byte_with_correct_crc) {
84 uint8_t original[] = {0x44, 0, 0, 0, 0};
85 uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
86 expect(byte_stuffer_send_frame,
87 when(size, is_equal_to(sizeof(expected))),
88 when(data, is_equal_to_contents_of(expected, sizeof(expected)))
89 );
90 validator_send_frame(0, original, 1);
91}
92
93Ensure(FrameValidator, sends_five_bytes_with_correct_crc) {
94 uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
95 uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
96 expect(byte_stuffer_send_frame,
97 when(size, is_equal_to(sizeof(expected))),
98 when(data, is_equal_to_contents_of(expected, sizeof(expected)))
99 );
100 validator_send_frame(0, original, 5);
101}
diff --git a/quantum/serial_link/tests/transport_tests.c b/quantum/serial_link/tests/transport_tests.c
new file mode 100644
index 000000000..358e1b9fd
--- /dev/null
+++ b/quantum/serial_link/tests/transport_tests.c
@@ -0,0 +1,168 @@
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 <cgreen/cgreen.h>
26#include <cgreen/mocks.h>
27#include "serial_link/protocol/transport.c"
28#include "serial_link/protocol/triple_buffered_object.c"
29
30void signal_data_written(void) {
31 mock();
32}
33
34static uint8_t sent_data[2048];
35static uint16_t sent_data_size;
36
37void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
38 mock(destination);
39 memcpy(sent_data + sent_data_size, data, size);
40 sent_data_size += size;
41}
42
43typedef struct {
44 uint32_t test;
45} test_object1_t;
46
47typedef struct {
48 uint32_t test1;
49 uint32_t test2;
50} test_object2_t;
51
52MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t);
53MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t);
54SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t);
55
56static remote_object_t* test_remote_objects[] = {
57 REMOTE_OBJECT(master_to_slave),
58 REMOTE_OBJECT(master_to_single_slave),
59 REMOTE_OBJECT(slave_to_master),
60};
61
62Describe(Transport);
63BeforeEach(Transport) {
64 add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
65 sent_data_size = 0;
66}
67AfterEach(Transport) {}
68
69Ensure(Transport, write_to_local_signals_an_event) {
70 begin_write_master_to_slave();
71 expect(signal_data_written);
72 end_write_master_to_slave();
73 begin_write_slave_to_master();
74 expect(signal_data_written);
75 end_write_slave_to_master();
76 begin_write_master_to_single_slave(1);
77 expect(signal_data_written);
78 end_write_master_to_single_slave(1);
79}
80
81Ensure(Transport, writes_from_master_to_all_slaves) {
82 update_transport();
83 test_object1_t* obj = begin_write_master_to_slave();
84 obj->test = 5;
85 expect(signal_data_written);
86 end_write_master_to_slave();
87 expect(router_send_frame,
88 when(destination, is_equal_to(0xFF)));
89 update_transport();
90 transport_recv_frame(0, sent_data, sent_data_size);
91 test_object1_t* obj2 = read_master_to_slave();
92 assert_that(obj2, is_not_equal_to(NULL));
93 assert_that(obj2->test, is_equal_to(5));
94}
95
96Ensure(Transport, writes_from_slave_to_master) {
97 update_transport();
98 test_object1_t* obj = begin_write_slave_to_master();
99 obj->test = 7;
100 expect(signal_data_written);
101 end_write_slave_to_master();
102 expect(router_send_frame,
103 when(destination, is_equal_to(0)));
104 update_transport();
105 transport_recv_frame(3, sent_data, sent_data_size);
106 test_object1_t* obj2 = read_slave_to_master(2);
107 assert_that(read_slave_to_master(0), is_equal_to(NULL));
108 assert_that(obj2, is_not_equal_to(NULL));
109 assert_that(obj2->test, is_equal_to(7));
110}
111
112Ensure(Transport, writes_from_master_to_single_slave) {
113 update_transport();
114 test_object1_t* obj = begin_write_master_to_single_slave(3);
115 obj->test = 7;
116 expect(signal_data_written);
117 end_write_master_to_single_slave(3);
118 expect(router_send_frame,
119 when(destination, is_equal_to(4)));
120 update_transport();
121 transport_recv_frame(0, sent_data, sent_data_size);
122 test_object1_t* obj2 = read_master_to_single_slave();
123 assert_that(obj2, is_not_equal_to(NULL));
124 assert_that(obj2->test, is_equal_to(7));
125}
126
127Ensure(Transport, ignores_object_with_invalid_id) {
128 update_transport();
129 test_object1_t* obj = begin_write_master_to_single_slave(3);
130 obj->test = 7;
131 expect(signal_data_written);
132 end_write_master_to_single_slave(3);
133 expect(router_send_frame,
134 when(destination, is_equal_to(4)));
135 update_transport();
136 sent_data[sent_data_size - 1] = 44;
137 transport_recv_frame(0, sent_data, sent_data_size);
138 test_object1_t* obj2 = read_master_to_single_slave();
139 assert_that(obj2, is_equal_to(NULL));
140}
141
142Ensure(Transport, ignores_object_with_size_too_small) {
143 update_transport();
144 test_object1_t* obj = begin_write_master_to_slave();
145 obj->test = 7;
146 expect(signal_data_written);
147 end_write_master_to_slave();
148 expect(router_send_frame);
149 update_transport();
150 sent_data[sent_data_size - 2] = 0;
151 transport_recv_frame(0, sent_data, sent_data_size - 1);
152 test_object1_t* obj2 = read_master_to_slave();
153 assert_that(obj2, is_equal_to(NULL));
154}
155
156Ensure(Transport, ignores_object_with_size_too_big) {
157 update_transport();
158 test_object1_t* obj = begin_write_master_to_slave();
159 obj->test = 7;
160 expect(signal_data_written);
161 end_write_master_to_slave();
162 expect(router_send_frame);
163 update_transport();
164 sent_data[sent_data_size + 21] = 0;
165 transport_recv_frame(0, sent_data, sent_data_size + 22);
166 test_object1_t* obj2 = read_master_to_slave();
167 assert_that(obj2, is_equal_to(NULL));
168}
diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.c b/quantum/serial_link/tests/triple_buffered_object_tests.c
new file mode 100644
index 000000000..6f7c82b46
--- /dev/null
+++ b/quantum/serial_link/tests/triple_buffered_object_tests.c
@@ -0,0 +1,82 @@
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 <cgreen/cgreen.h>
26#include "serial_link/protocol/triple_buffered_object.c"
27
28typedef struct {
29 uint8_t state;
30 uint32_t buffer[3];
31}test_object_t;
32
33test_object_t test_object;
34
35Describe(TripleBufferedObject);
36BeforeEach(TripleBufferedObject) {
37 triple_buffer_init((triple_buffer_object_t*)&test_object);
38}
39AfterEach(TripleBufferedObject) {}
40
41
42Ensure(TripleBufferedObject, writes_and_reads_object) {
43 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
44 triple_buffer_end_write(&test_object);
45 assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC));
46}
47
48Ensure(TripleBufferedObject, does_not_read_empty) {
49 assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
50}
51
52Ensure(TripleBufferedObject, writes_twice_and_reads_object) {
53 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
54 triple_buffer_end_write(&test_object);
55 *triple_buffer_begin_write(&test_object) = 0x44778899;
56 triple_buffer_end_write(&test_object);
57 assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899));
58}
59
60Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
61 *triple_buffer_begin_write(&test_object) = 1;
62 triple_buffer_end_write(&test_object);
63 uint32_t* read = triple_buffer_read(&test_object);
64 *triple_buffer_begin_write(&test_object) = 2;
65 triple_buffer_end_write(&test_object);
66 assert_that(*read, is_equal_to(1));
67 assert_that(*triple_buffer_read(&test_object), is_equal_to(2));
68 assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
69}
70
71Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
72 *triple_buffer_begin_write(&test_object) = 1;
73 triple_buffer_end_write(&test_object);
74 uint32_t* read = triple_buffer_read(&test_object);
75 *triple_buffer_begin_write(&test_object) = 2;
76 triple_buffer_end_write(&test_object);
77 *triple_buffer_begin_write(&test_object) = 3;
78 triple_buffer_end_write(&test_object);
79 assert_that(*read, is_equal_to(1));
80 assert_that(*triple_buffer_read(&test_object), is_equal_to(3));
81 assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
82}
diff --git a/quantum/template/Makefile b/quantum/template/Makefile
new file mode 100644
index 000000000..3f6d133c9
--- /dev/null
+++ b/quantum/template/Makefile
@@ -0,0 +1,75 @@
1
2
3# MCU name
4#MCU = at90usb1287
5MCU = atmega32u4
6
7# Processor frequency.
8# This will define a symbol, F_CPU, in all source code files equal to the
9# processor frequency in Hz. You can then use this symbol in your source code to
10# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
11# automatically to create a 32-bit value in your source code.
12#
13# This will be an integer division of F_USB below, as it is sourced by
14# F_USB after it has run through any CPU prescalers. Note that this value
15# does not *change* the processor frequency - it should merely be updated to
16# reflect the processor speed set externally so that the code can use accurate
17# software delays.
18F_CPU = 16000000
19
20
21#
22# LUFA specific
23#
24# Target architecture (see library "Board Types" documentation).
25ARCH = AVR8
26
27# Input clock frequency.
28# This will define a symbol, F_USB, in all source code files equal to the
29# input clock frequency (before any prescaling is performed) in Hz. This value may
30# differ from F_CPU if prescaling is used on the latter, and is required as the
31# raw input clock is fed directly to the PLL sections of the AVR for high speed
32# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
33# at the end, this will be done automatically to create a 32-bit value in your
34# source code.
35#
36# If no clock division is performed on the input clock inside the AVR (via the
37# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
38F_USB = $(F_CPU)
39
40# Interrupt driven control endpoint task(+60)
41OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
42
43
44# Boot Section Size in *bytes*
45# Teensy halfKay 512
46# Teensy++ halfKay 1024
47# Atmel DFU loader 4096
48# LUFA bootloader 4096
49# USBaspLoader 2048
50OPT_DEFS += -DBOOTLOADER_SIZE=512
51
52
53# Build Options
54# change yes to no to disable
55#
56BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000)
57MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700)
58EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450)
59CONSOLE_ENABLE ?= yes # Console for debug(+400)
60COMMAND_ENABLE ?= yes # Commands for debug and configuration
61# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
62SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend
63# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
64NKRO_ENABLE ?= no # USB Nkey Rollover
65BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default
66MIDI_ENABLE ?= no # MIDI controls
67UNICODE_ENABLE ?= no # Unicode
68BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID
69AUDIO_ENABLE ?= no # Audio output on port C6
70
71ifndef QUANTUM_DIR
72 include ../../Makefile
73endif
74
75
diff --git a/quantum/template/config.h b/quantum/template/config.h
new file mode 100644
index 000000000..b02f0c7eb
--- /dev/null
+++ b/quantum/template/config.h
@@ -0,0 +1,162 @@
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#ifndef CONFIG_H
19#define CONFIG_H
20
21#include "config_common.h"
22
23/* USB Device descriptor parameter */
24#define VENDOR_ID 0xFEED
25#define PRODUCT_ID 0x6060
26#define DEVICE_VER 0x0001
27#define MANUFACTURER You
28#define PRODUCT %KEYBOARD%
29#define DESCRIPTION A custom keyboard
30
31/* key matrix size */
32#define MATRIX_ROWS 2
33#define MATRIX_COLS 3
34
35/*
36 * Keyboard Matrix Assignments
37 *
38 * Change this to how you wired your keyboard
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
48
49/* COL2ROW or ROW2COL */
50#define DIODE_DIRECTION COL2ROW
51
52// #define BACKLIGHT_PIN B7
53// #define BACKLIGHT_BREATHING
54// #define BACKLIGHT_LEVELS 3
55
56
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) */
61//#define MATRIX_HAS_GHOST
62
63/* number of backlight levels */
64
65/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
66#define LOCKING_SUPPORT_ENABLE
67/* Locking resynchronize hack */
68#define LOCKING_RESYNC_ENABLE
69
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 */
104#define IS_COMMAND() ( \
105 keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
106)
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
144/*
145 * Feature disable options
146 * These options are also useful to firmware size reduction.
147 */
148
149/* disable debug print */
150//#define NO_DEBUG
151
152/* disable print */
153//#define NO_PRINT
154
155/* disable action features */
156//#define NO_ACTION_LAYER
157//#define NO_ACTION_TAPPING
158//#define NO_ACTION_ONESHOT
159//#define NO_ACTION_MACRO
160//#define NO_ACTION_FUNCTION
161
162#endif
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/keymap.c b/quantum/template/keymaps/default/keymap.c
new file mode 100644
index 000000000..e28a4723e
--- /dev/null
+++ b/quantum/template/keymaps/default/keymap.c
@@ -0,0 +1,44 @@
1#include "%KEYBOARD%.h"
2
3const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
4[0] = KEYMAP( /* Base */
5 KC_A, KC_1, KC_H, \
6 KC_TAB, KC_SPC \
7),
8};
9
10const uint16_t PROGMEM fn_actions[] = {
11
12};
13
14const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
15{
16 // MACRODOWN only works in this function
17 switch(id) {
18 case 0:
19 if (record->event.pressed) {
20 register_code(KC_RSFT);
21 } else {
22 unregister_code(KC_RSFT);
23 }
24 break;
25 }
26 return MACRO_NONE;
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
new file mode 100644
index 000000000..b2fb4dd98
--- /dev/null
+++ b/quantum/template/readme.md
@@ -0,0 +1,28 @@
1%KEYBOARD% keyboard firmware
2======================
3
4## Quantum MK Firmware
5
6For the full Quantum feature list, see [the parent readme.md](/doc/readme.md).
7
8## Building
9
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
12Depending on which keymap you would like to use, you will have to compile slightly differently.
13
14### Default
15
16To build with the default keymap, simply run `make`.
17
18### Other Keymaps
19
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 `keymap` option like:
23
24```
25$ make keymap=[default|jack|<name>]
26```
27
28Keymaps follow the format **__keymap.c__** and are stored in folders in the `keymaps` folder, eg `keymaps/my_keymap/` \ No newline at end of file
diff --git a/quantum/template/template.c b/quantum/template/template.c
new file mode 100644
index 000000000..dcc4b0a22
--- /dev/null
+++ b/quantum/template/template.c
@@ -0,0 +1,28 @@
1#include "%KEYBOARD%.h"
2
3void matrix_init_kb(void) {
4 // put your keyboard start-up code here
5 // runs once when the firmware starts up
6
7 matrix_init_user();
8}
9
10void matrix_scan_kb(void) {
11 // put your looping keyboard code here
12 // runs every cycle (a lot)
13
14 matrix_scan_user();
15}
16
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_action_user(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
new file mode 100644
index 000000000..cd78a54e3
--- /dev/null
+++ b/quantum/template/template.h
@@ -0,0 +1,19 @@
1#ifndef %KEYBOARD_UPPERCASE%_H
2#define %KEYBOARD_UPPERCASE%_H
3
4#include "quantum.h"
5
6// This a shortcut to help you visually see your layout.
7// The following is an example using the Planck MIT layout
8// The first section contains all of the arguements
9// The second converts the arguments into a two-dimensional array
10#define KEYMAP( \
11 k00, k01, k02, \
12 k10, k11 \
13) \
14{ \
15 { k00, k01, k02 }, \
16 { k10, KC_NO, k11 }, \
17}
18
19#endif
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/visualizer/.gitmodules b/quantum/visualizer/.gitmodules
new file mode 100644
index 000000000..b320458c0
--- /dev/null
+++ b/quantum/visualizer/.gitmodules
@@ -0,0 +1,3 @@
1[submodule "ugfx"]
2 path = ugfx
3 url = https://bitbucket.org/fredizzimo/ugfx.git
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/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/ugfx b/quantum/visualizer/ugfx
new file mode 160000
Subproject e221a690616e20f87e0b0088baffdbd5427be86
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
new file mode 100644
index 000000000..605be3059
--- /dev/null
+++ b/quantum/visualizer/visualizer.c
@@ -0,0 +1,481 @@
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 "ch.h"
27#include "config.h"
28#include <string.h>
29
30#ifdef LCD_ENABLE
31#include "gfx.h"
32#endif
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 USE_SERIAL_LINK
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 event_source_t layer_changed_event;
72static bool visualizer_enabled = false;
73
74#define MAX_SIMULTANEOUS_ANIMATIONS 4
75static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
76
77#ifdef USE_SERIAL_LINK
78MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t);
79
80static remote_object_t* remote_objects[] = {
81 REMOTE_OBJECT(current_status),
82};
83
84#endif
85
86
87void start_keyframe_animation(keyframe_animation_t* animation) {
88 animation->current_frame = -1;
89 animation->time_left_in_frame = 0;
90 animation->need_update = true;
91 int free_index = -1;
92 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
93 if (animations[i] == animation) {
94 return;
95 }
96 if (free_index == -1 && animations[i] == NULL) {
97 free_index=i;
98 }
99 }
100 if (free_index!=-1) {
101 animations[free_index] = animation;
102 }
103}
104
105void stop_keyframe_animation(keyframe_animation_t* animation) {
106 animation->current_frame = animation->num_frames;
107 animation->time_left_in_frame = 0;
108 animation->need_update = true;
109 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
110 if (animations[i] == animation) {
111 animations[i] = NULL;
112 return;
113 }
114 }
115}
116
117void stop_all_keyframe_animations(void) {
118 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
119 if (animations[i]) {
120 animations[i]->current_frame = animations[i]->num_frames;
121 animations[i]->time_left_in_frame = 0;
122 animations[i]->need_update = true;
123 animations[i] = NULL;
124 }
125 }
126}
127
128static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systime_t delta, systime_t* sleep_time) {
129 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
130 animation->time_left_in_frame, delta);
131 if (animation->current_frame == animation->num_frames) {
132 animation->need_update = false;
133 return false;
134 }
135 if (animation->current_frame == -1) {
136 animation->current_frame = 0;
137 animation->time_left_in_frame = animation->frame_lengths[0];
138 animation->need_update = true;
139 } else {
140 animation->time_left_in_frame -= delta;
141 while (animation->time_left_in_frame <= 0) {
142 int left = animation->time_left_in_frame;
143 if (animation->need_update) {
144 animation->time_left_in_frame = 0;
145 (*animation->frame_functions[animation->current_frame])(animation, state);
146 }
147 animation->current_frame++;
148 animation->need_update = true;
149 if (animation->current_frame == animation->num_frames) {
150 if (animation->loop) {
151 animation->current_frame = 0;
152 }
153 else {
154 stop_keyframe_animation(animation);
155 return false;
156 }
157 }
158 delta = -left;
159 animation->time_left_in_frame = animation->frame_lengths[animation->current_frame];
160 animation->time_left_in_frame -= delta;
161 }
162 }
163 if (animation->need_update) {
164 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
165 }
166
167 int wanted_sleep = animation->need_update ? 10 : animation->time_left_in_frame;
168 if ((unsigned)wanted_sleep < *sleep_time) {
169 *sleep_time = wanted_sleep;
170 }
171
172 return true;
173}
174
175bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
176 (void)animation;
177 (void)state;
178 return false;
179}
180
181#ifdef LCD_BACKLIGHT_ENABLE
182bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
183 int frame_length = animation->frame_lengths[animation->current_frame];
184 int current_pos = frame_length - animation->time_left_in_frame;
185 uint8_t t_h = LCD_HUE(state->target_lcd_color);
186 uint8_t t_s = LCD_SAT(state->target_lcd_color);
187 uint8_t t_i = LCD_INT(state->target_lcd_color);
188 uint8_t p_h = LCD_HUE(state->prev_lcd_color);
189 uint8_t p_s = LCD_SAT(state->prev_lcd_color);
190 uint8_t p_i = LCD_INT(state->prev_lcd_color);
191
192 uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around
193 int d_h2 = t_h - p_h;
194 // Chose the shortest way around
195 int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1;
196 int d_s = t_s - p_s;
197 int d_i = t_i - p_i;
198
199 int hue = (d_h * current_pos) / frame_length;
200 int sat = (d_s * current_pos) / frame_length;
201 int intensity = (d_i * current_pos) / frame_length;
202 //dprintf("%X -> %X = %X\n", p_h, t_h, hue);
203 hue += p_h;
204 sat += p_s;
205 intensity += p_i;
206 state->current_lcd_color = LCD_COLOR(hue, sat, intensity);
207 lcd_backlight_color(
208 LCD_HUE(state->current_lcd_color),
209 LCD_SAT(state->current_lcd_color),
210 LCD_INT(state->current_lcd_color));
211
212 return true;
213}
214
215bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
216 (void)animation;
217 state->prev_lcd_color = state->target_lcd_color;
218 state->current_lcd_color = state->target_lcd_color;
219 lcd_backlight_color(
220 LCD_HUE(state->current_lcd_color),
221 LCD_SAT(state->current_lcd_color),
222 LCD_INT(state->current_lcd_color));
223 return false;
224}
225#endif // LCD_BACKLIGHT_ENABLE
226
227#ifdef LCD_ENABLE
228bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) {
229 (void)animation;
230 gdispClear(White);
231 gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black);
232 gdispFlush();
233 return false;
234}
235
236static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) {
237 for (int i=0; i<16;i++)
238 {
239 uint32_t mask = (1u << i);
240 if (default_layer & mask) {
241 if (layer & mask) {
242 *buffer = 'B';
243 } else {
244 *buffer = 'D';
245 }
246 } else if (layer & mask) {
247 *buffer = '1';
248 } else {
249 *buffer = '0';
250 }
251 ++buffer;
252
253 if (i==3 || i==7 || i==11) {
254 *buffer = ' ';
255 ++buffer;
256 }
257 }
258 *buffer = 0;
259}
260
261bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
262 (void)animation;
263 const char* layer_help = "1=On D=Default B=Both";
264 char layer_buffer[16 + 4]; // 3 spaces and one null terminator
265 gdispClear(White);
266 gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black);
267 format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer);
268 gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black);
269 format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer);
270 gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black);
271 gdispFlush();
272 return false;
273}
274#endif // LCD_ENABLE
275
276bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
277 (void)animation;
278 (void)state;
279#ifdef LCD_ENABLE
280 gdispSetPowerMode(powerOff);
281#endif
282#ifdef LCD_BACKLIGHT_ENABLE
283 lcd_backlight_hal_color(0, 0, 0);
284#endif
285 return false;
286}
287
288bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
289 (void)animation;
290 (void)state;
291#ifdef LCD_ENABLE
292 gdispSetPowerMode(powerOn);
293#endif
294 return false;
295}
296
297bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) {
298 (void)animation;
299 (void)state;
300 dprint("User visualizer inited\n");
301 visualizer_enabled = true;
302 return false;
303}
304
305// TODO: Optimize the stack size, this is probably way too big
306static THD_WORKING_AREA(visualizerThreadStack, 1024);
307static THD_FUNCTION(visualizerThread, arg) {
308 (void)arg;
309
310 event_listener_t event_listener;
311 chEvtRegister(&layer_changed_event, &event_listener, 0);
312
313 visualizer_keyboard_status_t initial_status = {
314 .default_layer = 0xFFFFFFFF,
315 .layer = 0xFFFFFFFF,
316 .leds = 0xFFFFFFFF,
317 .suspended = false,
318 };
319
320 visualizer_state_t state = {
321 .status = initial_status,
322 .current_lcd_color = 0,
323#ifdef LCD_ENABLE
324 .font_fixed5x8 = gdispOpenFont("fixed_5x8"),
325 .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12")
326#endif
327 };
328 initialize_user_visualizer(&state);
329 state.prev_lcd_color = state.current_lcd_color;
330
331#ifdef LCD_BACKLIGHT_ENABLE
332 lcd_backlight_color(
333 LCD_HUE(state.current_lcd_color),
334 LCD_SAT(state.current_lcd_color),
335 LCD_INT(state.current_lcd_color));
336#endif
337
338 systime_t sleep_time = TIME_INFINITE;
339 systime_t current_time = chVTGetSystemTimeX();
340
341 while(true) {
342 systime_t new_time = chVTGetSystemTimeX();
343 systime_t delta = new_time - current_time;
344 current_time = new_time;
345 bool enabled = visualizer_enabled;
346 if (!same_status(&state.status, &current_status)) {
347 if (visualizer_enabled) {
348 if (current_status.suspended) {
349 stop_all_keyframe_animations();
350 visualizer_enabled = false;
351 state.status = current_status;
352 user_visualizer_suspend(&state);
353 }
354 else {
355 state.status = current_status;
356 update_user_visualizer_state(&state);
357 }
358 state.prev_lcd_color = state.current_lcd_color;
359 }
360 }
361 if (!enabled && state.status.suspended && current_status.suspended == false) {
362 // Setting the status to the initial status will force an update
363 // when the visualizer is enabled again
364 state.status = initial_status;
365 state.status.suspended = false;
366 stop_all_keyframe_animations();
367 user_visualizer_resume(&state);
368 state.prev_lcd_color = state.current_lcd_color;
369 }
370 sleep_time = TIME_INFINITE;
371 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
372 if (animations[i]) {
373 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
374 }
375 }
376 // The animation can enable the visualizer
377 // And we might need to update the state when that happens
378 // so don't sleep
379 if (enabled != visualizer_enabled) {
380 sleep_time = 0;
381 }
382
383 systime_t after_update = chVTGetSystemTimeX();
384 unsigned update_delta = after_update - current_time;
385 if (sleep_time != TIME_INFINITE) {
386 if (sleep_time > update_delta) {
387 sleep_time -= update_delta;
388 }
389 else {
390 sleep_time = 0;
391 }
392 }
393 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
394 chEvtWaitOneTimeout(EVENT_MASK(0), sleep_time);
395 }
396#ifdef LCD_ENABLE
397 gdispCloseFont(state.font_fixed5x8);
398 gdispCloseFont(state.font_dejavusansbold12);
399#endif
400}
401
402void visualizer_init(void) {
403#ifdef LCD_ENABLE
404 gfxInit();
405#endif
406
407#ifdef LCD_BACKLIGHT_ENABLE
408 lcd_backlight_init();
409#endif
410
411#ifdef USE_SERIAL_LINK
412 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) );
413#endif
414 // We are using a low priority thread, the idea is to have it run only
415 // when the main thread is sleeping during the matrix scanning
416 chEvtObjectInit(&layer_changed_event);
417 (void)chThdCreateStatic(visualizerThreadStack, sizeof(visualizerThreadStack),
418 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
419}
420
421void update_status(bool changed) {
422 if (changed) {
423 chEvtBroadcast(&layer_changed_event);
424 }
425#ifdef USE_SERIAL_LINK
426 static systime_t last_update = 0;
427 systime_t current_update = chVTGetSystemTimeX();
428 systime_t delta = current_update - last_update;
429 if (changed || delta > MS2ST(10)) {
430 last_update = current_update;
431 visualizer_keyboard_status_t* r = begin_write_current_status();
432 *r = current_status;
433 end_write_current_status();
434 }
435#endif
436}
437
438void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
439 // Note that there's a small race condition here, the thread could read
440 // a state where one of these are set but not the other. But this should
441 // not really matter as it will be fixed during the next loop step.
442 // Alternatively a mutex could be used instead of the volatile variables
443
444 bool changed = false;
445#ifdef USE_SERIAL_LINK
446 if (is_serial_link_connected ()) {
447 visualizer_keyboard_status_t* new_status = read_current_status();
448 if (new_status) {
449 if (!same_status(&current_status, new_status)) {
450 changed = true;
451 current_status = *new_status;
452 }
453 }
454 }
455 else {
456#else
457 {
458#endif
459 visualizer_keyboard_status_t new_status = {
460 .layer = state,
461 .default_layer = default_state,
462 .leds = leds,
463 .suspended = current_status.suspended,
464 };
465 if (!same_status(&current_status, &new_status)) {
466 changed = true;
467 current_status = new_status;
468 }
469 }
470 update_status(changed);
471}
472
473void visualizer_suspend(void) {
474 current_status.suspended = true;
475 update_status(true);
476}
477
478void visualizer_resume(void) {
479 current_status.suspended = false;
480 update_status(true);
481}
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
new file mode 100644
index 000000000..22798cda6
--- /dev/null
+++ b/quantum/visualizer/visualizer.h
@@ -0,0 +1,131 @@
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#ifdef LCD_ENABLE
32#include "gfx.h"
33#endif
34
35#ifdef LCD_BACKLIGHT_ENABLE
36#include "lcd_backlight.h"
37#endif
38
39// This need to be called once at the start
40void visualizer_init(void);
41// This should be called at every matrix scan
42void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds);
43// This should be called when the keyboard goes to suspend state
44void visualizer_suspend(void);
45// This should be called when the keyboard wakes up from suspend state
46void visualizer_resume(void);
47
48// If you need support for more than 8 keyframes per animation, you can change this
49#define MAX_VISUALIZER_KEY_FRAMES 8
50
51struct keyframe_animation_t;
52
53typedef struct {
54 uint32_t layer;
55 uint32_t default_layer;
56 uint32_t leds; // See led.h for available statuses
57 bool suspended;
58} visualizer_keyboard_status_t;
59
60// The state struct is used by the various keyframe functions
61// It's also used for setting the LCD color and layer text
62// from the user customized code
63typedef struct visualizer_state_t {
64 // The user code should primarily be modifying these
65 uint32_t target_lcd_color;
66 const char* layer_text;
67
68 // The user visualizer(and animation functions) can read these
69 visualizer_keyboard_status_t status;
70
71 // These are used by the animation functions
72 uint32_t current_lcd_color;
73 uint32_t prev_lcd_color;
74#ifdef LCD_ENABLE
75 font_t font_fixed5x8;
76 font_t font_dejavusansbold12;
77#endif
78} visualizer_state_t;
79
80// Any custom keyframe function should have this signature
81// return true to get continuous updates, otherwise you will only get one
82// update per frame
83typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*);
84
85// Represents a keyframe animation, so fields are internal to the system
86// while others are meant to be initialized by the user code
87typedef struct keyframe_animation_t {
88 // These should be initialized
89 int num_frames;
90 bool loop;
91 int frame_lengths[MAX_VISUALIZER_KEY_FRAMES];
92 frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES];
93
94 // Used internally by the system, and can also be read by
95 // keyframe update functions
96 int current_frame;
97 int time_left_in_frame;
98 bool need_update;
99
100} keyframe_animation_t;
101
102void start_keyframe_animation(keyframe_animation_t* animation);
103void stop_keyframe_animation(keyframe_animation_t* animation);
104
105// Some predefined keyframe functions that can be used by the user code
106// Does nothing, useful for adding delays
107bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state);
108// Animates the LCD backlight color between the current color and the target color (of the state)
109bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
110// Sets the backlight color to the target color
111bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
112// Displays the layer text centered vertically on the screen
113bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
114// Displays a bitmap (0/1) of all the currently active layers
115bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
116
117bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
118bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
119
120// Call this once, when the initial animation has finished, alternatively you can call it
121// directly from the initalize_user_visualizer function (the animation can be null)
122bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state);
123
124// These two functions have to be implemented by the user
125void initialize_user_visualizer(visualizer_state_t* state);
126void update_user_visualizer_state(visualizer_state_t* state);
127void user_visualizer_suspend(visualizer_state_t* state);
128void user_visualizer_resume(visualizer_state_t* state);
129
130
131#endif /* VISUALIZER_H */
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
new file mode 100644
index 000000000..13c5d3158
--- /dev/null
+++ b/quantum/visualizer/visualizer.mk
@@ -0,0 +1,41 @@
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
23GFXLIB = $(VISUALIZER_DIR)/ugfx
24ifdef LCD_ENABLE
25include $(GFXLIB)/gfx.mk
26UDEFS += -DLCD_ENABLE
27ULIBS += -lm
28endif
29SRC += $(GFXSRC) $(VISUALIZER_DIR)/visualizer.c
30UINCDIR += $(GFXINC) $(VISUALIZER_DIR)
31
32ifdef LCD_BACKLIGHT_ENABLE
33SRC += $(VISUALIZER_DIR)/lcd_backlight.c
34SRC += lcd_backlight_hal.c
35UDEFS += -DLCD_BACKLIGHT_ENABLE
36endif
37
38ifndef VISUALIZER_USER
39VISUALIZER_USER = visualizer_user.c
40endif
41SRC += $(VISUALIZER_USER) \ No newline at end of file