diff options
Diffstat (limited to 'quantum')
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 | |||
9 | static uint8_t aref = (1<<REFS0); // default to AREF = Vcc | ||
10 | |||
11 | |||
12 | void analogReference(uint8_t mode) | ||
13 | { | ||
14 | aref = mode & 0xC0; | ||
15 | } | ||
16 | |||
17 | |||
18 | // Arduino compatible pin input | ||
19 | int16_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 | ||
36 | int16_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 | |||
6 | void analogReference(uint8_t mode); | ||
7 | int16_t analogRead(uint8_t pin); | ||
8 | int16_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 | |||
36 | int voices = 0; | ||
37 | int voice_place = 0; | ||
38 | float frequency = 0; | ||
39 | int volume = 0; | ||
40 | long position = 0; | ||
41 | |||
42 | float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
43 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
44 | bool sliding = false; | ||
45 | |||
46 | float place = 0; | ||
47 | |||
48 | uint8_t * sample; | ||
49 | uint16_t sample_length = 0; | ||
50 | |||
51 | bool playing_notes = false; | ||
52 | bool playing_note = false; | ||
53 | float note_frequency = 0; | ||
54 | float note_length = 0; | ||
55 | uint8_t note_tempo = TEMPO_DEFAULT; | ||
56 | float note_timbre = TIMBRE_DEFAULT; | ||
57 | uint16_t note_position = 0; | ||
58 | float (* notes_pointer)[][2]; | ||
59 | uint16_t notes_count; | ||
60 | bool notes_repeat; | ||
61 | float notes_rest; | ||
62 | bool note_resting = false; | ||
63 | |||
64 | uint8_t current_note = 0; | ||
65 | uint8_t rest_counter = 0; | ||
66 | |||
67 | #ifdef VIBRATO_ENABLE | ||
68 | float vibrato_counter = 0; | ||
69 | float vibrato_strength = .5; | ||
70 | float vibrato_rate = 0.125; | ||
71 | #endif | ||
72 | |||
73 | float polyphony_rate = 0; | ||
74 | |||
75 | static bool audio_initialized = false; | ||
76 | |||
77 | audio_config_t audio_config; | ||
78 | |||
79 | uint16_t envelope_index = 0; | ||
80 | |||
81 | void 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 | |||
106 | void 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 | |||
128 | void 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 | |||
165 | float mod(float a, int b) | ||
166 | { | ||
167 | float r = fmod(a, b); | ||
168 | return r < 0 ? r + b : r; | ||
169 | } | ||
170 | |||
171 | float 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 | |||
183 | ISR(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 | |||
308 | void 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 | |||
337 | void 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 | |||
373 | bool is_playing_notes(void) { | ||
374 | return playing_notes; | ||
375 | } | ||
376 | |||
377 | bool is_audio_on(void) { | ||
378 | return (audio_config.enable != 0); | ||
379 | } | ||
380 | |||
381 | void 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 | |||
388 | void audio_on(void) { | ||
389 | audio_config.enable = 1; | ||
390 | eeconfig_update_audio(audio_config.raw); | ||
391 | audio_on_user(); | ||
392 | } | ||
393 | |||
394 | void 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 | |||
403 | void set_vibrato_rate(float rate) { | ||
404 | vibrato_rate = rate; | ||
405 | } | ||
406 | |||
407 | void increase_vibrato_rate(float change) { | ||
408 | vibrato_rate *= change; | ||
409 | } | ||
410 | |||
411 | void decrease_vibrato_rate(float change) { | ||
412 | vibrato_rate /= change; | ||
413 | } | ||
414 | |||
415 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
416 | |||
417 | void set_vibrato_strength(float strength) { | ||
418 | vibrato_strength = strength; | ||
419 | } | ||
420 | |||
421 | void increase_vibrato_strength(float change) { | ||
422 | vibrato_strength *= change; | ||
423 | } | ||
424 | |||
425 | void 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 | |||
435 | void set_polyphony_rate(float rate) { | ||
436 | polyphony_rate = rate; | ||
437 | } | ||
438 | |||
439 | void enable_polyphony() { | ||
440 | polyphony_rate = 5; | ||
441 | } | ||
442 | |||
443 | void disable_polyphony() { | ||
444 | polyphony_rate = 0; | ||
445 | } | ||
446 | |||
447 | void increase_polyphony_rate(float change) { | ||
448 | polyphony_rate *= change; | ||
449 | } | ||
450 | |||
451 | void decrease_polyphony_rate(float change) { | ||
452 | polyphony_rate /= change; | ||
453 | } | ||
454 | |||
455 | // Timbre function | ||
456 | |||
457 | void set_timbre(float timbre) { | ||
458 | note_timbre = timbre; | ||
459 | } | ||
460 | |||
461 | // Tempo functions | ||
462 | |||
463 | void set_tempo(uint8_t tempo) { | ||
464 | note_tempo = tempo; | ||
465 | } | ||
466 | |||
467 | void decrease_tempo(uint8_t tempo_change) { | ||
468 | note_tempo += tempo_change; | ||
469 | } | ||
470 | |||
471 | void 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 | |||
21 | typedef union { | ||
22 | uint8_t raw; | ||
23 | struct { | ||
24 | bool enable :1; | ||
25 | uint8_t level :7; | ||
26 | }; | ||
27 | } audio_config_t; | ||
28 | |||
29 | bool is_audio_on(void); | ||
30 | void audio_toggle(void); | ||
31 | void audio_on(void); | ||
32 | void audio_off(void); | ||
33 | |||
34 | // Vibrato rate functions | ||
35 | |||
36 | #ifdef VIBRATO_ENABLE | ||
37 | |||
38 | void set_vibrato_rate(float rate); | ||
39 | void increase_vibrato_rate(float change); | ||
40 | void decrease_vibrato_rate(float change); | ||
41 | |||
42 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
43 | |||
44 | void set_vibrato_strength(float strength); | ||
45 | void increase_vibrato_strength(float change); | ||
46 | void decrease_vibrato_strength(float change); | ||
47 | |||
48 | #endif | ||
49 | |||
50 | #endif | ||
51 | |||
52 | // Polyphony functions | ||
53 | |||
54 | void set_polyphony_rate(float rate); | ||
55 | void enable_polyphony(void); | ||
56 | void disable_polyphony(void); | ||
57 | void increase_polyphony_rate(float change); | ||
58 | void decrease_polyphony_rate(float change); | ||
59 | |||
60 | void set_timbre(float timbre); | ||
61 | void set_tempo(uint8_t tempo); | ||
62 | |||
63 | void increase_tempo(uint8_t tempo_change); | ||
64 | void decrease_tempo(uint8_t tempo_change); | ||
65 | |||
66 | void audio_init(void); | ||
67 | |||
68 | #ifdef PWM_AUDIO | ||
69 | void play_sample(uint8_t * s, uint16_t l, bool r); | ||
70 | #endif | ||
71 | void play_note(float freq, int vol); | ||
72 | void stop_note(float freq); | ||
73 | void stop_all_notes(void); | ||
74 | void 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(¬e_array, NOTE_ARRAY_SIZE((note_array)), (note_repeat), (note_rest_style)); | ||
87 | |||
88 | |||
89 | bool 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 | |||
47 | void delay_us(int count) { | ||
48 | while(count--) { | ||
49 | _delay_us(1); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | int voices = 0; | ||
54 | int voice_place = 0; | ||
55 | float frequency = 0; | ||
56 | int volume = 0; | ||
57 | long position = 0; | ||
58 | |||
59 | float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
60 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
61 | bool sliding = false; | ||
62 | |||
63 | float place = 0; | ||
64 | |||
65 | uint8_t * sample; | ||
66 | uint16_t sample_length = 0; | ||
67 | // float freq = 0; | ||
68 | |||
69 | bool playing_notes = false; | ||
70 | bool playing_note = false; | ||
71 | float note_frequency = 0; | ||
72 | float note_length = 0; | ||
73 | uint8_t note_tempo = TEMPO_DEFAULT; | ||
74 | float note_timbre = TIMBRE_DEFAULT; | ||
75 | uint16_t note_position = 0; | ||
76 | float (* notes_pointer)[][2]; | ||
77 | uint16_t notes_count; | ||
78 | bool notes_repeat; | ||
79 | float notes_rest; | ||
80 | bool note_resting = false; | ||
81 | |||
82 | uint8_t current_note = 0; | ||
83 | uint8_t rest_counter = 0; | ||
84 | |||
85 | #ifdef VIBRATO_ENABLE | ||
86 | float vibrato_counter = 0; | ||
87 | float vibrato_strength = .5; | ||
88 | float vibrato_rate = 0.125; | ||
89 | #endif | ||
90 | |||
91 | float polyphony_rate = 0; | ||
92 | |||
93 | static bool audio_initialized = false; | ||
94 | |||
95 | audio_config_t audio_config; | ||
96 | |||
97 | uint16_t envelope_index = 0; | ||
98 | |||
99 | void 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 | |||
148 | void 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 | |||
172 | void 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 | |||
216 | float mod(float a, int b) | ||
217 | { | ||
218 | float r = fmod(a, b); | ||
219 | return r < 0 ? r + b : r; | ||
220 | } | ||
221 | |||
222 | float 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 | |||
234 | ISR(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 | |||
434 | void 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 | |||
470 | void 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 | ||
516 | void 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 | |||
535 | void audio_toggle(void) { | ||
536 | audio_config.enable ^= 1; | ||
537 | eeconfig_update_audio(audio_config.raw); | ||
538 | } | ||
539 | |||
540 | void audio_on(void) { | ||
541 | audio_config.enable = 1; | ||
542 | eeconfig_update_audio(audio_config.raw); | ||
543 | } | ||
544 | |||
545 | void 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 | |||
554 | void set_vibrato_rate(float rate) { | ||
555 | vibrato_rate = rate; | ||
556 | } | ||
557 | |||
558 | void increase_vibrato_rate(float change) { | ||
559 | vibrato_rate *= change; | ||
560 | } | ||
561 | |||
562 | void decrease_vibrato_rate(float change) { | ||
563 | vibrato_rate /= change; | ||
564 | } | ||
565 | |||
566 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
567 | |||
568 | void set_vibrato_strength(float strength) { | ||
569 | vibrato_strength = strength; | ||
570 | } | ||
571 | |||
572 | void increase_vibrato_strength(float change) { | ||
573 | vibrato_strength *= change; | ||
574 | } | ||
575 | |||
576 | void 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 | |||
586 | void set_polyphony_rate(float rate) { | ||
587 | polyphony_rate = rate; | ||
588 | } | ||
589 | |||
590 | void enable_polyphony() { | ||
591 | polyphony_rate = 5; | ||
592 | } | ||
593 | |||
594 | void disable_polyphony() { | ||
595 | polyphony_rate = 0; | ||
596 | } | ||
597 | |||
598 | void increase_polyphony_rate(float change) { | ||
599 | polyphony_rate *= change; | ||
600 | } | ||
601 | |||
602 | void decrease_polyphony_rate(float change) { | ||
603 | polyphony_rate /= change; | ||
604 | } | ||
605 | |||
606 | // Timbre function | ||
607 | |||
608 | void set_timbre(float timbre) { | ||
609 | note_timbre = timbre; | ||
610 | } | ||
611 | |||
612 | // Tempo functions | ||
613 | |||
614 | void set_tempo(uint8_t tempo) { | ||
615 | note_tempo = tempo; | ||
616 | } | ||
617 | |||
618 | void decrease_tempo(uint8_t tempo_change) { | ||
619 | note_tempo += tempo_change; | ||
620 | } | ||
621 | |||
622 | void 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)) | ||
635 | void play_startup_tone() | ||
636 | { | ||
637 | } | ||
638 | |||
639 | __attribute__ ((weak)) | ||
640 | void 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 | |||
6 | const 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 | |||
30 | const 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 | |||
12 | extern const float vibrato_lut[VIBRATO_LUT_LENGTH]; | ||
13 | extern 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 | ||
6 | extern uint16_t envelope_index; | ||
7 | extern float note_timbre; | ||
8 | extern float polyphony_rate; | ||
9 | |||
10 | voice_type voice = default_voice; | ||
11 | |||
12 | void set_voice(voice_type v) { | ||
13 | voice = v; | ||
14 | } | ||
15 | |||
16 | void voice_iterate() { | ||
17 | voice = (voice + 1) % number_of_voices; | ||
18 | } | ||
19 | |||
20 | void voice_deiterate() { | ||
21 | voice = (voice - 1) % number_of_voices; | ||
22 | } | ||
23 | |||
24 | float 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 | |||
10 | float voice_envelope(float frequency); | ||
11 | |||
12 | typedef 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 | |||
27 | void set_voice(voice_type v); | ||
28 | void voice_iterate(void); | ||
29 | void 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 | |||
7 | const uint8_t sinewave[] PROGMEM= //2048 values | ||
8 | { | ||
9 | 0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82, | ||
10 | 0x83,0x83,0x83,0x84,0x84,0x85,0x85,0x85, | ||
11 | 0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88, | ||
12 | 0x89,0x89,0x8a,0x8a,0x8a,0x8b,0x8b,0x8c, | ||
13 | 0x8c,0x8c,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f, | ||
14 | 0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92, | ||
15 | 0x92,0x93,0x93,0x93,0x94,0x94,0x95,0x95, | ||
16 | 0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98, | ||
17 | 0x98,0x99,0x99,0x9a,0x9a,0x9a,0x9b,0x9b, | ||
18 | 0x9b,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e, | ||
19 | 0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1, | ||
20 | 0xa2,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4, | ||
21 | 0xa5,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7, | ||
22 | 0xa7,0xa8,0xa8,0xa9,0xa9,0xa9,0xaa,0xaa, | ||
23 | 0xaa,0xab,0xab,0xac,0xac,0xac,0xad,0xad, | ||
24 | 0xad,0xae,0xae,0xae,0xaf,0xaf,0xb0,0xb0, | ||
25 | 0xb0,0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb3, | ||
26 | 0xb3,0xb4,0xb4,0xb4,0xb5,0xb5,0xb5,0xb6, | ||
27 | 0xb6,0xb6,0xb7,0xb7,0xb7,0xb8,0xb8,0xb8, | ||
28 | 0xb9,0xb9,0xba,0xba,0xba,0xbb,0xbb,0xbb, | ||
29 | 0xbc,0xbc,0xbc,0xbd,0xbd,0xbd,0xbe,0xbe, | ||
30 | 0xbe,0xbf,0xbf,0xbf,0xc0,0xc0,0xc0,0xc1, | ||
31 | 0xc1,0xc1,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3, | ||
32 | 0xc4,0xc4,0xc4,0xc5,0xc5,0xc5,0xc6,0xc6, | ||
33 | 0xc6,0xc7,0xc7,0xc7,0xc8,0xc8,0xc8,0xc9, | ||
34 | 0xc9,0xc9,0xca,0xca,0xca,0xcb,0xcb,0xcb, | ||
35 | 0xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce, | ||
36 | 0xce,0xce,0xcf,0xcf,0xcf,0xcf,0xd0,0xd0, | ||
37 | 0xd0,0xd1,0xd1,0xd1,0xd2,0xd2,0xd2,0xd2, | ||
38 | 0xd3,0xd3,0xd3,0xd4,0xd4,0xd4,0xd5,0xd5, | ||
39 | 0xd5,0xd5,0xd6,0xd6,0xd6,0xd7,0xd7,0xd7, | ||
40 | 0xd7,0xd8,0xd8,0xd8,0xd9,0xd9,0xd9,0xd9, | ||
41 | 0xda,0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdc, | ||
42 | 0xdc,0xdc,0xdc,0xdd,0xdd,0xdd,0xdd,0xde, | ||
43 | 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xe0, | ||
44 | 0xe0,0xe0,0xe1,0xe1,0xe1,0xe1,0xe2,0xe2, | ||
45 | 0xe2,0xe2,0xe3,0xe3,0xe3,0xe3,0xe4,0xe4, | ||
46 | 0xe4,0xe4,0xe4,0xe5,0xe5,0xe5,0xe5,0xe6, | ||
47 | 0xe6,0xe6,0xe6,0xe7,0xe7,0xe7,0xe7,0xe8, | ||
48 | 0xe8,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xe9, | ||
49 | 0xea,0xea,0xea,0xea,0xea,0xeb,0xeb,0xeb, | ||
50 | 0xeb,0xeb,0xec,0xec,0xec,0xec,0xec,0xed, | ||
51 | 0xed,0xed,0xed,0xed,0xee,0xee,0xee,0xee, | ||
52 | 0xee,0xef,0xef,0xef,0xef,0xef,0xf0,0xf0, | ||
53 | 0xf0,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf1, | ||
54 | 0xf1,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf3, | ||
55 | 0xf3,0xf3,0xf3,0xf3,0xf3,0xf4,0xf4,0xf4, | ||
56 | 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5, | ||
57 | 0xf5,0xf5,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, | ||
58 | 0xf6,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, | ||
59 | 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, | ||
60 | 0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, | ||
61 | 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, | ||
62 | 0xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb, | ||
63 | 0xfb,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfc, | ||
64 | 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, | ||
65 | 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, | ||
66 | 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfe,0xfe, | ||
67 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
68 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
69 | 0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff, | ||
70 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
71 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
72 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
73 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
74 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
75 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
76 | 0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe, | ||
77 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
78 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
79 | 0xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfd,0xfd, | ||
80 | 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, | ||
81 | 0xfd,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, | ||
82 | 0xfc,0xfc,0xfc,0xfc,0xfc,0xfb,0xfb,0xfb, | ||
83 | 0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfa, | ||
84 | 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, | ||
85 | 0xfa,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, | ||
86 | 0xf9,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, | ||
87 | 0xf8,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, | ||
88 | 0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf5, | ||
89 | 0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf4,0xf4, | ||
90 | 0xf4,0xf4,0xf4,0xf4,0xf3,0xf3,0xf3,0xf3, | ||
91 | 0xf3,0xf3,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2, | ||
92 | 0xf1,0xf1,0xf1,0xf1,0xf1,0xf0,0xf0,0xf0, | ||
93 | 0xf0,0xf0,0xf0,0xef,0xef,0xef,0xef,0xef, | ||
94 | 0xee,0xee,0xee,0xee,0xee,0xed,0xed,0xed, | ||
95 | 0xed,0xed,0xec,0xec,0xec,0xec,0xec,0xeb, | ||
96 | 0xeb,0xeb,0xeb,0xeb,0xea,0xea,0xea,0xea, | ||
97 | 0xea,0xe9,0xe9,0xe9,0xe9,0xe8,0xe8,0xe8, | ||
98 | 0xe8,0xe8,0xe7,0xe7,0xe7,0xe7,0xe6,0xe6, | ||
99 | 0xe6,0xe6,0xe5,0xe5,0xe5,0xe5,0xe4,0xe4, | ||
100 | 0xe4,0xe4,0xe4,0xe3,0xe3,0xe3,0xe3,0xe2, | ||
101 | 0xe2,0xe2,0xe2,0xe1,0xe1,0xe1,0xe1,0xe0, | ||
102 | 0xe0,0xe0,0xe0,0xdf,0xdf,0xdf,0xde,0xde, | ||
103 | 0xde,0xde,0xdd,0xdd,0xdd,0xdd,0xdc,0xdc, | ||
104 | 0xdc,0xdc,0xdb,0xdb,0xdb,0xda,0xda,0xda, | ||
105 | 0xda,0xd9,0xd9,0xd9,0xd9,0xd8,0xd8,0xd8, | ||
106 | 0xd7,0xd7,0xd7,0xd7,0xd6,0xd6,0xd6,0xd5, | ||
107 | 0xd5,0xd5,0xd5,0xd4,0xd4,0xd4,0xd3,0xd3, | ||
108 | 0xd3,0xd2,0xd2,0xd2,0xd2,0xd1,0xd1,0xd1, | ||
109 | 0xd0,0xd0,0xd0,0xcf,0xcf,0xcf,0xcf,0xce, | ||
110 | 0xce,0xce,0xcd,0xcd,0xcd,0xcc,0xcc,0xcc, | ||
111 | 0xcb,0xcb,0xcb,0xcb,0xca,0xca,0xca,0xc9, | ||
112 | 0xc9,0xc9,0xc8,0xc8,0xc8,0xc7,0xc7,0xc7, | ||
113 | 0xc6,0xc6,0xc6,0xc5,0xc5,0xc5,0xc4,0xc4, | ||
114 | 0xc4,0xc3,0xc3,0xc3,0xc2,0xc2,0xc2,0xc1, | ||
115 | 0xc1,0xc1,0xc0,0xc0,0xc0,0xbf,0xbf,0xbf, | ||
116 | 0xbe,0xbe,0xbe,0xbd,0xbd,0xbd,0xbc,0xbc, | ||
117 | 0xbc,0xbb,0xbb,0xbb,0xba,0xba,0xba,0xb9, | ||
118 | 0xb9,0xb8,0xb8,0xb8,0xb7,0xb7,0xb7,0xb6, | ||
119 | 0xb6,0xb6,0xb5,0xb5,0xb5,0xb4,0xb4,0xb4, | ||
120 | 0xb3,0xb3,0xb2,0xb2,0xb2,0xb1,0xb1,0xb1, | ||
121 | 0xb0,0xb0,0xb0,0xaf,0xaf,0xae,0xae,0xae, | ||
122 | 0xad,0xad,0xad,0xac,0xac,0xac,0xab,0xab, | ||
123 | 0xaa,0xaa,0xaa,0xa9,0xa9,0xa9,0xa8,0xa8, | ||
124 | 0xa7,0xa7,0xa7,0xa6,0xa6,0xa6,0xa5,0xa5, | ||
125 | 0xa5,0xa4,0xa4,0xa3,0xa3,0xa3,0xa2,0xa2, | ||
126 | 0xa2,0xa1,0xa1,0xa0,0xa0,0xa0,0x9f,0x9f, | ||
127 | 0x9e,0x9e,0x9e,0x9d,0x9d,0x9d,0x9c,0x9c, | ||
128 | 0x9b,0x9b,0x9b,0x9a,0x9a,0x9a,0x99,0x99, | ||
129 | 0x98,0x98,0x98,0x97,0x97,0x96,0x96,0x96, | ||
130 | 0x95,0x95,0x95,0x94,0x94,0x93,0x93,0x93, | ||
131 | 0x92,0x92,0x91,0x91,0x91,0x90,0x90,0x8f, | ||
132 | 0x8f,0x8f,0x8e,0x8e,0x8e,0x8d,0x8d,0x8c, | ||
133 | 0x8c,0x8c,0x8b,0x8b,0x8a,0x8a,0x8a,0x89, | ||
134 | 0x89,0x88,0x88,0x88,0x87,0x87,0x87,0x86, | ||
135 | 0x86,0x85,0x85,0x85,0x84,0x84,0x83,0x83, | ||
136 | 0x83,0x82,0x82,0x81,0x81,0x81,0x80,0x80, | ||
137 | 0x80,0x7f,0x7f,0x7e,0x7e,0x7e,0x7d,0x7d, | ||
138 | 0x7c,0x7c,0x7c,0x7b,0x7b,0x7a,0x7a,0x7a, | ||
139 | 0x79,0x79,0x78,0x78,0x78,0x77,0x77,0x77, | ||
140 | 0x76,0x76,0x75,0x75,0x75,0x74,0x74,0x73, | ||
141 | 0x73,0x73,0x72,0x72,0x71,0x71,0x71,0x70, | ||
142 | 0x70,0x70,0x6f,0x6f,0x6e,0x6e,0x6e,0x6d, | ||
143 | 0x6d,0x6c,0x6c,0x6c,0x6b,0x6b,0x6a,0x6a, | ||
144 | 0x6a,0x69,0x69,0x69,0x68,0x68,0x67,0x67, | ||
145 | 0x67,0x66,0x66,0x65,0x65,0x65,0x64,0x64, | ||
146 | 0x64,0x63,0x63,0x62,0x62,0x62,0x61,0x61, | ||
147 | 0x61,0x60,0x60,0x5f,0x5f,0x5f,0x5e,0x5e, | ||
148 | 0x5d,0x5d,0x5d,0x5c,0x5c,0x5c,0x5b,0x5b, | ||
149 | 0x5a,0x5a,0x5a,0x59,0x59,0x59,0x58,0x58, | ||
150 | 0x58,0x57,0x57,0x56,0x56,0x56,0x55,0x55, | ||
151 | 0x55,0x54,0x54,0x53,0x53,0x53,0x52,0x52, | ||
152 | 0x52,0x51,0x51,0x51,0x50,0x50,0x4f,0x4f, | ||
153 | 0x4f,0x4e,0x4e,0x4e,0x4d,0x4d,0x4d,0x4c, | ||
154 | 0x4c,0x4b,0x4b,0x4b,0x4a,0x4a,0x4a,0x49, | ||
155 | 0x49,0x49,0x48,0x48,0x48,0x47,0x47,0x47, | ||
156 | 0x46,0x46,0x45,0x45,0x45,0x44,0x44,0x44, | ||
157 | 0x43,0x43,0x43,0x42,0x42,0x42,0x41,0x41, | ||
158 | 0x41,0x40,0x40,0x40,0x3f,0x3f,0x3f,0x3e, | ||
159 | 0x3e,0x3e,0x3d,0x3d,0x3d,0x3c,0x3c,0x3c, | ||
160 | 0x3b,0x3b,0x3b,0x3a,0x3a,0x3a,0x39,0x39, | ||
161 | 0x39,0x38,0x38,0x38,0x37,0x37,0x37,0x36, | ||
162 | 0x36,0x36,0x35,0x35,0x35,0x34,0x34,0x34, | ||
163 | 0x34,0x33,0x33,0x33,0x32,0x32,0x32,0x31, | ||
164 | 0x31,0x31,0x30,0x30,0x30,0x30,0x2f,0x2f, | ||
165 | 0x2f,0x2e,0x2e,0x2e,0x2d,0x2d,0x2d,0x2d, | ||
166 | 0x2c,0x2c,0x2c,0x2b,0x2b,0x2b,0x2a,0x2a, | ||
167 | 0x2a,0x2a,0x29,0x29,0x29,0x28,0x28,0x28, | ||
168 | 0x28,0x27,0x27,0x27,0x26,0x26,0x26,0x26, | ||
169 | 0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x23, | ||
170 | 0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x21, | ||
171 | 0x21,0x21,0x21,0x20,0x20,0x20,0x1f,0x1f, | ||
172 | 0x1f,0x1f,0x1e,0x1e,0x1e,0x1e,0x1d,0x1d, | ||
173 | 0x1d,0x1d,0x1c,0x1c,0x1c,0x1c,0x1b,0x1b, | ||
174 | 0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x19, | ||
175 | 0x19,0x19,0x19,0x18,0x18,0x18,0x18,0x17, | ||
176 | 0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16, | ||
177 | 0x15,0x15,0x15,0x15,0x15,0x14,0x14,0x14, | ||
178 | 0x14,0x14,0x13,0x13,0x13,0x13,0x13,0x12, | ||
179 | 0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11, | ||
180 | 0x11,0x10,0x10,0x10,0x10,0x10,0xf,0xf, | ||
181 | 0xf,0xf,0xf,0xf,0xe,0xe,0xe,0xe, | ||
182 | 0xe,0xd,0xd,0xd,0xd,0xd,0xd,0xc, | ||
183 | 0xc,0xc,0xc,0xc,0xc,0xb,0xb,0xb, | ||
184 | 0xb,0xb,0xb,0xa,0xa,0xa,0xa,0xa, | ||
185 | 0xa,0xa,0x9,0x9,0x9,0x9,0x9,0x9, | ||
186 | 0x9,0x8,0x8,0x8,0x8,0x8,0x8,0x8, | ||
187 | 0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7, | ||
188 | 0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x6, | ||
189 | 0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5, | ||
190 | 0x5,0x5,0x4,0x4,0x4,0x4,0x4,0x4, | ||
191 | 0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3, | ||
192 | 0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3, | ||
193 | 0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, | ||
194 | 0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x1, | ||
195 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
196 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
197 | 0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0, | ||
198 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
199 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
200 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
201 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
202 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
203 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
204 | 0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1, | ||
205 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
206 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
207 | 0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2, | ||
208 | 0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, | ||
209 | 0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3, | ||
210 | 0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4, | ||
211 | 0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5, | ||
212 | 0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5, | ||
213 | 0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6, | ||
214 | 0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x7, | ||
215 | 0x7,0x8,0x8,0x8,0x8,0x8,0x8,0x8, | ||
216 | 0x9,0x9,0x9,0x9,0x9,0x9,0x9,0xa, | ||
217 | 0xa,0xa,0xa,0xa,0xa,0xa,0xb,0xb, | ||
218 | 0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc, | ||
219 | 0xc,0xc,0xd,0xd,0xd,0xd,0xd,0xd, | ||
220 | 0xe,0xe,0xe,0xe,0xe,0xf,0xf,0xf, | ||
221 | 0xf,0xf,0xf,0x10,0x10,0x10,0x10,0x10, | ||
222 | 0x11,0x11,0x11,0x11,0x11,0x12,0x12,0x12, | ||
223 | 0x12,0x12,0x13,0x13,0x13,0x13,0x13,0x14, | ||
224 | 0x14,0x14,0x14,0x14,0x15,0x15,0x15,0x15, | ||
225 | 0x15,0x16,0x16,0x16,0x16,0x17,0x17,0x17, | ||
226 | 0x17,0x17,0x18,0x18,0x18,0x18,0x19,0x19, | ||
227 | 0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1b,0x1b, | ||
228 | 0x1b,0x1b,0x1b,0x1c,0x1c,0x1c,0x1c,0x1d, | ||
229 | 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x1e,0x1f, | ||
230 | 0x1f,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21, | ||
231 | 0x21,0x21,0x22,0x22,0x22,0x22,0x23,0x23, | ||
232 | 0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x25, | ||
233 | 0x25,0x26,0x26,0x26,0x26,0x27,0x27,0x27, | ||
234 | 0x28,0x28,0x28,0x28,0x29,0x29,0x29,0x2a, | ||
235 | 0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,0x2c,0x2c, | ||
236 | 0x2c,0x2d,0x2d,0x2d,0x2d,0x2e,0x2e,0x2e, | ||
237 | 0x2f,0x2f,0x2f,0x30,0x30,0x30,0x30,0x31, | ||
238 | 0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x33, | ||
239 | 0x34,0x34,0x34,0x34,0x35,0x35,0x35,0x36, | ||
240 | 0x36,0x36,0x37,0x37,0x37,0x38,0x38,0x38, | ||
241 | 0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b, | ||
242 | 0x3b,0x3c,0x3c,0x3c,0x3d,0x3d,0x3d,0x3e, | ||
243 | 0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40, | ||
244 | 0x41,0x41,0x41,0x42,0x42,0x42,0x43,0x43, | ||
245 | 0x43,0x44,0x44,0x44,0x45,0x45,0x45,0x46, | ||
246 | 0x46,0x47,0x47,0x47,0x48,0x48,0x48,0x49, | ||
247 | 0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b, | ||
248 | 0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4e, | ||
249 | 0x4f,0x4f,0x4f,0x50,0x50,0x51,0x51,0x51, | ||
250 | 0x52,0x52,0x52,0x53,0x53,0x53,0x54,0x54, | ||
251 | 0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57, | ||
252 | 0x58,0x58,0x58,0x59,0x59,0x59,0x5a,0x5a, | ||
253 | 0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d, | ||
254 | 0x5d,0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60, | ||
255 | 0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, | ||
256 | 0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66, | ||
257 | 0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x69, | ||
258 | 0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c, | ||
259 | 0x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x70, | ||
260 | 0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x73, | ||
261 | 0x73,0x73,0x74,0x74,0x75,0x75,0x75,0x76, | ||
262 | 0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79, | ||
263 | 0x79,0x7a,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c, | ||
264 | 0x7c,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 | |||
3 | extern keymap_config_t keymap_config; | ||
4 | |||
5 | uint16_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 | |||
4 | uint16_t keycode_config(uint16_t keycode); | ||
5 | |||
6 | /* NOTE: Not portable. Bit field order depends on implementation */ | ||
7 | typedef 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 | |||
21 | extern 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 | /* | ||
2 | Copyright 2012,2013 Jun Wako <wakojun@gmail.com> | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along 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 */ | ||
42 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); | ||
43 | |||
44 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | ||
45 | extern const uint16_t fn_actions[]; | ||
46 | |||
47 | enum 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 | /* | ||
2 | Copyright 2012,2013 Jun Wako <wakojun@gmail.com> | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along 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 | |||
36 | extern keymap_config_t keymap_config; | ||
37 | |||
38 | #include <inttypes.h> | ||
39 | |||
40 | /* converts key to action */ | ||
41 | action_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)) | ||
149 | const uint16_t PROGMEM fn_actions[] = { | ||
150 | |||
151 | }; | ||
152 | |||
153 | /* Macro */ | ||
154 | __attribute__ ((weak)) | ||
155 | const 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)) | ||
162 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
163 | { | ||
164 | } | ||
165 | |||
166 | /* translates key to keycode */ | ||
167 | uint16_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 | ||
20 | void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) | ||
21 | { | ||
22 | ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); | ||
23 | } | ||
24 | |||
25 | void 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 | ||
33 | void 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 | |||
40 | void 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 | |||
106 | void 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) | ||
124 | w_nop1 | ||
125 | #endif | ||
126 | #if (w1_nops&2) | ||
127 | w_nop2 | ||
128 | #endif | ||
129 | #if (w1_nops&4) | ||
130 | w_nop4 | ||
131 | #endif | ||
132 | #if (w1_nops&8) | ||
133 | w_nop8 | ||
134 | #endif | ||
135 | #if (w1_nops&16) | ||
136 | w_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) | ||
158 | w_nop1 | ||
159 | #endif | ||
160 | #if (w3_nops&2) | ||
161 | w_nop2 | ||
162 | #endif | ||
163 | #if (w3_nops&4) | ||
164 | w_nop4 | ||
165 | #endif | ||
166 | #if (w3_nops&8) | ||
167 | w_nop8 | ||
168 | #endif | ||
169 | #if (w3_nops&16) | ||
170 | w_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 | |||
27 | struct cRGB { uint8_t g; uint8_t r; uint8_t b; }; | ||
28 | struct 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 | |||
45 | void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds); | ||
46 | void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask); | ||
47 | void 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 | |||
56 | void ws2812_sendarray (uint8_t *array,uint16_t length); | ||
57 | void 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 | /* | ||
2 | Copyright 2012 Jun Wako | ||
3 | Copyright 2014 Jack Humbert | ||
4 | |||
5 | This program is free software: you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation, either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along 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 | ||
34 | static uint8_t debouncing = DEBOUNCING_DELAY; | ||
35 | |||
36 | static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; | ||
37 | static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; | ||
38 | |||
39 | /* matrix state(1:on, 0:off) */ | ||
40 | static matrix_row_t matrix[MATRIX_ROWS]; | ||
41 | static 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 | |||
54 | static matrix_row_t read_cols(void); | ||
55 | static void init_cols(void); | ||
56 | static void unselect_rows(void); | ||
57 | static void select_row(uint8_t row); | ||
58 | |||
59 | __attribute__ ((weak)) | ||
60 | void matrix_init_quantum(void) { | ||
61 | matrix_init_kb(); | ||
62 | } | ||
63 | |||
64 | __attribute__ ((weak)) | ||
65 | void matrix_scan_quantum(void) { | ||
66 | matrix_scan_kb(); | ||
67 | } | ||
68 | |||
69 | __attribute__ ((weak)) | ||
70 | void matrix_init_kb(void) { | ||
71 | matrix_init_user(); | ||
72 | } | ||
73 | |||
74 | __attribute__ ((weak)) | ||
75 | void matrix_scan_kb(void) { | ||
76 | matrix_scan_user(); | ||
77 | } | ||
78 | |||
79 | __attribute__ ((weak)) | ||
80 | void matrix_init_user(void) { | ||
81 | } | ||
82 | |||
83 | __attribute__ ((weak)) | ||
84 | void matrix_scan_user(void) { | ||
85 | } | ||
86 | |||
87 | inline | ||
88 | uint8_t matrix_rows(void) { | ||
89 | return MATRIX_ROWS; | ||
90 | } | ||
91 | |||
92 | inline | ||
93 | uint8_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 | |||
121 | void 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 | |||
141 | uint8_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 | |||
206 | bool matrix_is_modified(void) | ||
207 | { | ||
208 | if (debouncing) return false; | ||
209 | return true; | ||
210 | } | ||
211 | |||
212 | inline | ||
213 | bool matrix_is_on(uint8_t row, uint8_t col) | ||
214 | { | ||
215 | return (matrix[row] & ((matrix_row_t)1<col)); | ||
216 | } | ||
217 | |||
218 | inline | ||
219 | matrix_row_t matrix_get_row(uint8_t row) | ||
220 | { | ||
221 | return matrix[row]; | ||
222 | } | ||
223 | |||
224 | void 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 | |||
234 | uint8_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 | |||
243 | static 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 | |||
257 | static 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 | |||
273 | static 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 | |||
287 | static 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 | |||
3 | bool 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 | |||
25 | bool 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 | ||
8 | bool chording = false; | ||
9 | |||
10 | uint8_t chord_keys[CHORDING_MAX] = {0}; | ||
11 | uint8_t chord_key_count = 0; | ||
12 | uint8_t chord_key_down = 0; | ||
13 | |||
14 | bool 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)) | ||
4 | void leader_start(void) {} | ||
5 | |||
6 | __attribute__ ((weak)) | ||
7 | void leader_end(void) {} | ||
8 | |||
9 | // Leader key stuff | ||
10 | bool leading = false; | ||
11 | uint16_t leader_time = 0; | ||
12 | |||
13 | uint16_t leader_sequence[5] = {0, 0, 0, 0, 0}; | ||
14 | uint8_t leader_sequence_size = 0; | ||
15 | |||
16 | bool 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 | |||
6 | bool process_leader(uint16_t keycode, keyrecord_t *record); | ||
7 | |||
8 | void leader_start(void); | ||
9 | void 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 | |||
3 | bool midi_activated = false; | ||
4 | uint8_t starting_note = 0x0C; | ||
5 | int offset = 7; | ||
6 | |||
7 | bool 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 | |||
6 | bool 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 | |||
3 | bool music_activated = false; | ||
4 | uint8_t starting_note = 0x0C; | ||
5 | int offset = 7; | ||
6 | |||
7 | // music sequencer | ||
8 | static bool music_sequence_recording = false; | ||
9 | static bool music_sequence_playing = false; | ||
10 | static float music_sequence[16] = {0}; | ||
11 | static uint8_t music_sequence_count = 0; | ||
12 | static uint8_t music_sequence_position = 0; | ||
13 | |||
14 | static uint16_t music_sequence_timer = 0; | ||
15 | static uint16_t music_sequence_interval = 100; | ||
16 | |||
17 | bool 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 | |||
130 | bool is_music_on(void) { | ||
131 | return (music_activated != 0); | ||
132 | } | ||
133 | |||
134 | void music_toggle(void) { | ||
135 | if (!music_activated) { | ||
136 | music_on(); | ||
137 | } else { | ||
138 | music_off(); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | void music_on(void) { | ||
143 | music_activated = 1; | ||
144 | music_on_user(); | ||
145 | } | ||
146 | |||
147 | void music_off(void) { | ||
148 | music_activated = 0; | ||
149 | stop_all_notes(); | ||
150 | } | ||
151 | |||
152 | |||
153 | __attribute__ ((weak)) | ||
154 | void music_on_user() {} | ||
155 | |||
156 | __attribute__ ((weak)) | ||
157 | void audio_on_user() {} | ||
158 | |||
159 | __attribute__ ((weak)) | ||
160 | void music_scale_user() {} | ||
161 | |||
162 | void 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 | |||
6 | bool process_music(uint16_t keycode, keyrecord_t *record); | ||
7 | |||
8 | bool is_music_on(void); | ||
9 | void music_toggle(void); | ||
10 | void music_on(void); | ||
11 | void music_off(void); | ||
12 | |||
13 | void audio_on_user(void); | ||
14 | void music_on_user(void); | ||
15 | void music_scale_user(void); | ||
16 | |||
17 | void 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 | |||
3 | static qk_tap_dance_state_t qk_tap_dance_state; | ||
4 | |||
5 | static 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 | |||
22 | static 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 | |||
28 | void 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 | |||
49 | bool 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 | |||
79 | void 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 | |||
87 | void 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 | |||
9 | typedef 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 | |||
18 | typedef enum | ||
19 | { | ||
20 | QK_TAP_DANCE_TYPE_PAIR, | ||
21 | QK_TAP_DANCE_TYPE_FN, | ||
22 | } qk_tap_dance_type_t; | ||
23 | |||
24 | typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state); | ||
25 | |||
26 | typedef 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 | |||
48 | extern const qk_tap_dance_action_t tap_dance_actions[]; | ||
49 | |||
50 | /* To be used internally */ | ||
51 | |||
52 | bool process_tap_dance(uint16_t keycode, keyrecord_t *record); | ||
53 | void matrix_scan_tap_dance (void); | ||
54 | void 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 | |||
3 | static uint8_t input_mode; | ||
4 | |||
5 | uint16_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 | |||
16 | void set_unicode_mode(uint8_t os_target) | ||
17 | { | ||
18 | input_mode = os_target; | ||
19 | } | ||
20 | |||
21 | bool 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 | |||
11 | void set_unicode_input_mode(uint8_t os_target); | ||
12 | |||
13 | bool 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)) | ||
4 | bool process_action_kb(keyrecord_t *record) { | ||
5 | return true; | ||
6 | } | ||
7 | |||
8 | __attribute__ ((weak)) | ||
9 | bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | ||
10 | return process_record_user(keycode, record); | ||
11 | } | ||
12 | |||
13 | __attribute__ ((weak)) | ||
14 | bool 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 | |||
27 | static bool shift_interrupted[2] = {0, 0}; | ||
28 | |||
29 | bool 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 | |||
200 | const 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 | |||
219 | const 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 | |||
242 | const 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 | |||
261 | const 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 | |||
282 | void 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 | |||
302 | void 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 | |||
310 | void 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 | |||
348 | void matrix_init_quantum() { | ||
349 | #ifdef BACKLIGHT_ENABLE | ||
350 | backlight_init_ports(); | ||
351 | #endif | ||
352 | matrix_init_kb(); | ||
353 | } | ||
354 | |||
355 | void 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 | |||
368 | static 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)) | ||
384 | void 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)) | ||
416 | void 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 | |||
450 | static uint8_t breath_intensity; | ||
451 | static uint8_t breath_speed; | ||
452 | static uint16_t breathing_index; | ||
453 | static uint8_t breathing_halt; | ||
454 | |||
455 | void 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 | |||
473 | void 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 | |||
491 | void breathing_disable(void) | ||
492 | { | ||
493 | // Disable breathing interrupt | ||
494 | TIMSK1 &= ~_BV(OCIE1A); | ||
495 | backlight_set(get_backlight_level()); | ||
496 | } | ||
497 | |||
498 | void 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 | |||
512 | void 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 | |||
539 | bool is_breathing(void) | ||
540 | { | ||
541 | return (TIMSK1 && _BV(OCIE1A)); | ||
542 | } | ||
543 | |||
544 | void 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 | |||
550 | void breathing_intensity_set(uint8_t value) | ||
551 | { | ||
552 | breath_intensity = value; | ||
553 | } | ||
554 | |||
555 | void breathing_speed_default(void) | ||
556 | { | ||
557 | breath_speed = 4; | ||
558 | } | ||
559 | |||
560 | void 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 | |||
584 | void 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 | |||
596 | void 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 | |||
608 | void 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 | */ | ||
621 | static 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, | ||
624 | 255, 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 | |||
628 | ISR(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)) | ||
652 | void backlight_init_ports(void) | ||
653 | { | ||
654 | |||
655 | } | ||
656 | |||
657 | __attribute__ ((weak)) | ||
658 | void backlight_set(uint8_t level) | ||
659 | { | ||
660 | |||
661 | } | ||
662 | |||
663 | #endif // backlight | ||
664 | |||
665 | |||
666 | |||
667 | __attribute__ ((weak)) | ||
668 | void led_set_user(uint8_t usb_led) { | ||
669 | |||
670 | } | ||
671 | |||
672 | __attribute__ ((weak)) | ||
673 | void led_set_kb(uint8_t usb_led) { | ||
674 | led_set_user(usb_led); | ||
675 | } | ||
676 | |||
677 | __attribute__ ((weak)) | ||
678 | void led_init_ports(void) | ||
679 | { | ||
680 | |||
681 | } | ||
682 | |||
683 | __attribute__ ((weak)) | ||
684 | void 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)) | ||
712 | void startup_user() {} | ||
713 | |||
714 | __attribute__ ((weak)) | ||
715 | void 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 | |||
30 | extern 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)) | ||
62 | void send_string(const char *str); | ||
63 | |||
64 | // For tri-layer | ||
65 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); | ||
66 | |||
67 | void 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 | |||
72 | void matrix_init_kb(void); | ||
73 | void matrix_scan_kb(void); | ||
74 | void matrix_init_user(void); | ||
75 | void matrix_scan_user(void); | ||
76 | bool process_action_kb(keyrecord_t *record); | ||
77 | bool process_record_kb(uint16_t keycode, keyrecord_t *record); | ||
78 | bool process_record_user(uint16_t keycode, keyrecord_t *record); | ||
79 | |||
80 | void startup_user(void); | ||
81 | void shutdown_user(void); | ||
82 | |||
83 | #ifdef BACKLIGHT_ENABLE | ||
84 | void backlight_init_ports(void); | ||
85 | |||
86 | #ifdef BACKLIGHT_BREATHING | ||
87 | void breathing_enable(void); | ||
88 | void breathing_pulse(void); | ||
89 | void breathing_disable(void); | ||
90 | void breathing_self_disable(void); | ||
91 | void breathing_toggle(void); | ||
92 | bool is_breathing(void); | ||
93 | |||
94 | void breathing_defaults(void); | ||
95 | void breathing_intensity_default(void); | ||
96 | void breathing_speed_default(void); | ||
97 | void breathing_speed_set(uint8_t value); | ||
98 | void breathing_speed_inc(uint8_t value); | ||
99 | void breathing_speed_dec(uint8_t value); | ||
100 | #endif | ||
101 | |||
102 | #endif | ||
103 | |||
104 | void led_set_user(uint8_t usb_led); | ||
105 | void 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 | |||
9 | const 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 | }; | ||
27 | const 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}; | ||
28 | const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; | ||
29 | const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; | ||
30 | const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
31 | const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
32 | const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
33 | |||
34 | rgblight_config_t rgblight_config; | ||
35 | rgblight_config_t inmem_config; | ||
36 | struct cRGB led[RGBLED_NUM]; | ||
37 | uint8_t rgblight_inited = 0; | ||
38 | |||
39 | |||
40 | void 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 | |||
100 | void 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 | |||
107 | uint32_t eeconfig_read_rgblight(void) { | ||
108 | return eeprom_read_dword(EECONFIG_RGBLIGHT); | ||
109 | } | ||
110 | void eeconfig_update_rgblight(uint32_t val) { | ||
111 | eeprom_update_dword(EECONFIG_RGBLIGHT, val); | ||
112 | } | ||
113 | void 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 | } | ||
122 | void 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 | |||
131 | void 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 | |||
156 | void 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 | |||
164 | void 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 | |||
172 | void 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 | |||
181 | void 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 | |||
207 | void 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 | |||
221 | void 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 | } | ||
226 | void 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 | } | ||
235 | void 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 | } | ||
244 | void 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 | } | ||
253 | void 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 | } | ||
262 | void 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 | |||
272 | void 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 | } | ||
284 | void 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 | |||
307 | void 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 | |||
318 | void 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 | ||
332 | void 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 | } | ||
348 | void rgblight_timer_enable(void) { | ||
349 | TIMSK3 |= _BV(OCIE3A); | ||
350 | dprintf("TIMER3 enabled.\n"); | ||
351 | } | ||
352 | void rgblight_timer_disable(void) { | ||
353 | TIMSK3 &= ~_BV(OCIE3A); | ||
354 | dprintf("TIMER3 disabled.\n"); | ||
355 | } | ||
356 | void rgblight_timer_toggle(void) { | ||
357 | TIMSK3 ^= _BV(OCIE3A); | ||
358 | dprintf("TIMER3 toggled.\n"); | ||
359 | } | ||
360 | |||
361 | ISR(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 | ||
379 | void 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 | |||
390 | void 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 | |||
400 | void 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 | } | ||
424 | void 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 | |||
458 | void 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 | |||
40 | typedef 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 | |||
51 | void rgblight_init(void); | ||
52 | void rgblight_increase(void); | ||
53 | void rgblight_decrease(void); | ||
54 | void rgblight_toggle(void); | ||
55 | void rgblight_step(void); | ||
56 | void rgblight_mode(uint8_t mode); | ||
57 | void rgblight_set(void); | ||
58 | void rgblight_increase_hue(void); | ||
59 | void rgblight_decrease_hue(void); | ||
60 | void rgblight_increase_sat(void); | ||
61 | void rgblight_decrease_sat(void); | ||
62 | void rgblight_increase_val(void); | ||
63 | void rgblight_decrease_val(void); | ||
64 | void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val); | ||
65 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b); | ||
66 | |||
67 | uint32_t eeconfig_read_rgblight(void); | ||
68 | void eeconfig_update_rgblight(uint32_t val); | ||
69 | void eeconfig_update_rgblight_default(void); | ||
70 | void eeconfig_debug_rgblight(void); | ||
71 | |||
72 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); | ||
73 | void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1); | ||
74 | void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val); | ||
75 | |||
76 | void rgblight_timer_init(void); | ||
77 | void rgblight_timer_enable(void); | ||
78 | void rgblight_timer_disable(void); | ||
79 | void rgblight_timer_toggle(void); | ||
80 | void rgblight_effect_breathing(uint8_t interval); | ||
81 | void rgblight_effect_rainbow_mood(uint8_t interval); | ||
82 | void rgblight_effect_rainbow_swirl(uint8_t interval); | ||
83 | void rgblight_effect_snake(uint8_t interval); | ||
84 | void 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 @@ | |||
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. | ||
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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
37 | typedef 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 | |||
44 | static byte_stuffer_state_t states[NUM_LINKS]; | ||
45 | |||
46 | void 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 | |||
52 | void 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 | |||
59 | void 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 | |||
108 | static 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 | |||
115 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_BYTE_STUFFER_H | ||
26 | #define SERIAL_LINK_BYTE_STUFFER_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | void init_byte_stuffer(void); | ||
31 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data); | ||
32 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
29 | static bool is_master; | ||
30 | |||
31 | void router_set_master(bool master) { | ||
32 | is_master = master; | ||
33 | } | ||
34 | |||
35 | void 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 | |||
56 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
34 | void router_set_master(bool master); | ||
35 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
36 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
30 | const 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 | |||
98 | static 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 | |||
106 | void 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 | |||
117 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_FRAME_VALIDATOR_H | ||
26 | #define SERIAL_LINK_FRAME_VALIDATOR_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
31 | // The buffer pointed to by the data needs 4 additional bytes | ||
32 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_PHYSICAL_H | ||
26 | #define SERIAL_LINK_PHYSICAL_H | ||
27 | |||
28 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | ||
31 | static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS]; | ||
32 | static uint32_t num_remote_objects = 0; | ||
33 | |||
34 | void 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 | |||
72 | void 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 | |||
96 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | ||
37 | typedef enum { | ||
38 | MASTER_TO_ALL_SLAVES, | ||
39 | MASTER_TO_SINGLE_SLAVE, | ||
40 | SLAVE_TO_MASTER, | ||
41 | } remote_object_type; | ||
42 | |||
43 | typedef 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) \ | ||
55 | typedef 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 | |||
147 | void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); | ||
148 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); | ||
149 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
40 | void 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 | |||
48 | void* 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 | |||
65 | void* 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 | |||
70 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H | ||
26 | #define SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H | ||
27 | |||
28 | #include <stdint.h> | ||
29 | |||
30 | typedef struct { | ||
31 | uint8_t state; | ||
32 | uint8_t buffer[] __attribute__((aligned(4))); | ||
33 | }triple_buffer_object_t; | ||
34 | |||
35 | void 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 | |||
46 | void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object); | ||
47 | void triple_buffer_end_write_internal(triple_buffer_object_t* object); | ||
48 | void* 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
36 | static event_source_t new_data_event; | ||
37 | static bool serial_link_connected; | ||
38 | static bool is_master = false; | ||
39 | |||
40 | static uint8_t keyboard_leds(void); | ||
41 | static void send_keyboard(report_keyboard_t *report); | ||
42 | static void send_mouse(report_mouse_t *report); | ||
43 | static void send_system(uint16_t data); | ||
44 | static void send_consumer(uint16_t data); | ||
45 | |||
46 | host_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 | |||
63 | static SerialConfig config = { | ||
64 | .sc_speed = SERIAL_LINK_BAUD | ||
65 | }; | ||
66 | |||
67 | //#define DEBUG_LINK_ERRORS | ||
68 | |||
69 | static 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 | |||
82 | static 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 | |||
113 | bool is_serial_link_master(void) { | ||
114 | return is_master; | ||
115 | } | ||
116 | |||
117 | // TODO: Optimize the stack size, this is probably way too big | ||
118 | static THD_WORKING_AREA(serialThreadStack, 1024); | ||
119 | static 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 | |||
162 | void 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 | |||
171 | static systime_t last_update = 0; | ||
172 | |||
173 | typedef struct { | ||
174 | matrix_row_t rows[MATRIX_ROWS]; | ||
175 | } matrix_object_t; | ||
176 | |||
177 | static matrix_object_t last_matrix = {}; | ||
178 | |||
179 | SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t); | ||
180 | MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool); | ||
181 | |||
182 | static remote_object_t* remote_objects[] = { | ||
183 | REMOTE_OBJECT(serial_link_connected), | ||
184 | REMOTE_OBJECT(keyboard_matrix), | ||
185 | }; | ||
186 | |||
187 | void 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 | |||
199 | void matrix_set_remote(matrix_row_t* rows, uint8_t index); | ||
200 | |||
201 | void 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 | |||
233 | void signal_data_written(void) { | ||
234 | chEvtBroadcast(&new_data_event); | ||
235 | } | ||
236 | |||
237 | bool is_serial_link_connected(void) { | ||
238 | return serial_link_connected; | ||
239 | } | ||
240 | |||
241 | host_driver_t* get_serial_link_driver(void) { | ||
242 | return &serial_driver; | ||
243 | } | ||
244 | |||
245 | // NOTE: The driver does nothing, because the master handles everything | ||
246 | uint8_t keyboard_leds(void) { | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | void send_keyboard(report_keyboard_t *report) { | ||
251 | (void)report; | ||
252 | } | ||
253 | |||
254 | void send_mouse(report_mouse_t *report) { | ||
255 | (void)report; | ||
256 | } | ||
257 | |||
258 | void send_system(uint16_t data) { | ||
259 | (void)data; | ||
260 | } | ||
261 | |||
262 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef SERIAL_LINK_H | ||
26 | #define SERIAL_LINK_H | ||
27 | |||
28 | #include "host_driver.h" | ||
29 | #include <stdbool.h> | ||
30 | |||
31 | void init_serial_link(void); | ||
32 | void init_serial_link_hal(void); | ||
33 | bool is_serial_link_connected(void); | ||
34 | bool is_serial_link_master(void); | ||
35 | host_driver_t* get_serial_link_driver(void); | ||
36 | void serial_link_update(void); | ||
37 | |||
38 | #if defined(PROTOCOL_CHIBIOS) | ||
39 | #include "ch.h" | ||
40 | |||
41 | static inline void serial_link_lock(void) { | ||
42 | chSysLock(); | ||
43 | } | ||
44 | |||
45 | static inline void serial_link_unlock(void) { | ||
46 | chSysUnlock(); | ||
47 | } | ||
48 | |||
49 | void signal_data_written(void); | ||
50 | |||
51 | #else | ||
52 | |||
53 | inline void serial_link_lock(void) { | ||
54 | } | ||
55 | |||
56 | inline void serial_link_unlock(void) { | ||
57 | } | ||
58 | |||
59 | void 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 | |||
23 | CC = gcc | ||
24 | CFLAGS = | ||
25 | INCLUDES = -I. -I../../ | ||
26 | LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared | ||
27 | LDLIBS = -lcgreen | ||
28 | UNITOBJ = $(BUILDDIR)/serialtest/unitobj | ||
29 | DEPDIR = $(BUILDDIR)/serialtest/unit.d | ||
30 | UNITTESTS = $(BUILDDIR)/serialtest/unittests | ||
31 | DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td | ||
32 | EXT = .so | ||
33 | UNAME := $(shell uname) | ||
34 | ifneq (, $(findstring MINGW, $(UNAME))) | ||
35 | EXT = .dll | ||
36 | endif | ||
37 | ifneq (, $(findstring CYGWIN, $(UNAME))) | ||
38 | EXT = .dll | ||
39 | endif | ||
40 | |||
41 | SRC = $(wildcard *.c) | ||
42 | TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC)) | ||
43 | $(shell mkdir -p $(DEPDIR) >/dev/null) | ||
44 | |||
45 | test: $(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
32 | static uint8_t sent_data[MAX_FRAME_SIZE*2]; | ||
33 | static uint16_t sent_data_size; | ||
34 | |||
35 | Describe(ByteStuffer); | ||
36 | BeforeEach(ByteStuffer) { | ||
37 | init_byte_stuffer(); | ||
38 | sent_data_size = 0; | ||
39 | } | ||
40 | AfterEach(ByteStuffer) {} | ||
41 | |||
42 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
43 | mock(data, size); | ||
44 | } | ||
45 | |||
46 | void 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 | |||
51 | Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { | ||
52 | never_expect(validator_recv_frame); | ||
53 | byte_stuffer_recv_byte(0, 0); | ||
54 | } | ||
55 | |||
56 | Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { | ||
57 | never_expect(validator_recv_frame); | ||
58 | byte_stuffer_recv_byte(0, 0xFF); | ||
59 | } | ||
60 | |||
61 | Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) { | ||
62 | never_expect(validator_recv_frame); | ||
63 | byte_stuffer_recv_byte(0, 0x4A); | ||
64 | } | ||
65 | |||
66 | Ensure(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 | |||
72 | Ensure(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 | |||
83 | Ensure(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 | |||
96 | Ensure(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 | |||
107 | Ensure(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 | |||
121 | Ensure(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 | |||
141 | Ensure(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 | |||
156 | Ensure(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 | |||
172 | Ensure(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 | |||
189 | Ensure(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 | |||
209 | Ensure(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 | |||
229 | Ensure(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 | |||
264 | Ensure(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 | |||
278 | Ensure(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 | |||
290 | Ensure(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 | |||
306 | Ensure(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 | |||
311 | Ensure(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 | |||
319 | Ensure(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 | |||
327 | Ensure(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 | |||
335 | Ensure(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 | |||
343 | Ensure(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 | |||
351 | Ensure(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 | |||
359 | Ensure(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 | |||
367 | Ensure(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 | |||
375 | Ensure(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 | |||
392 | Ensure(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 | |||
411 | Ensure(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 | |||
431 | Ensure(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 | |||
444 | Ensure(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 | |||
457 | Ensure(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 | |||
473 | Ensure(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 | |||
491 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
32 | static uint8_t received_data[256]; | ||
33 | static uint16_t received_data_size; | ||
34 | |||
35 | typedef struct { | ||
36 | uint8_t sent_data[256]; | ||
37 | uint16_t sent_data_size; | ||
38 | } receive_buffer_t; | ||
39 | |||
40 | typedef struct { | ||
41 | receive_buffer_t send_buffers[2]; | ||
42 | } router_buffer_t; | ||
43 | |||
44 | router_buffer_t router_buffers[8]; | ||
45 | |||
46 | router_buffer_t* current_router_buffer; | ||
47 | |||
48 | |||
49 | Describe(FrameRouter); | ||
50 | BeforeEach(FrameRouter) { | ||
51 | init_byte_stuffer(); | ||
52 | memset(router_buffers, 0, sizeof(router_buffers)); | ||
53 | current_router_buffer = 0; | ||
54 | } | ||
55 | AfterEach(FrameRouter) {} | ||
56 | |||
57 | typedef struct { | ||
58 | uint32_t data; | ||
59 | uint8_t extra[16]; | ||
60 | } frame_buffer_t; | ||
61 | |||
62 | |||
63 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
64 | receive_buffer_t* buffer = ¤t_router_buffer->send_buffers[link]; | ||
65 | memcpy(buffer->sent_data + buffer->sent_data_size, data, size); | ||
66 | buffer->sent_data_size += size; | ||
67 | } | ||
68 | |||
69 | static 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 | |||
76 | static void activate_router(uint8_t num) { | ||
77 | current_router_buffer = router_buffers + num; | ||
78 | router_set_master(num==0); | ||
79 | } | ||
80 | |||
81 | static 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 | |||
95 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
96 | mock(from, data, size); | ||
97 | } | ||
98 | |||
99 | |||
100 | Ensure(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 | |||
127 | Ensure(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 | |||
158 | Ensure(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 | |||
176 | Ensure(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 | |||
198 | Ensure(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 | |||
207 | Ensure(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 | |||
216 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include <cgreen/cgreen.h> | ||
26 | #include <cgreen/mocks.h> | ||
27 | #include "serial_link/protocol/frame_validator.c" | ||
28 | |||
29 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
30 | mock(data, size); | ||
31 | } | ||
32 | |||
33 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
34 | mock(data, size); | ||
35 | } | ||
36 | |||
37 | Describe(FrameValidator); | ||
38 | BeforeEach(FrameValidator) {} | ||
39 | AfterEach(FrameValidator) {} | ||
40 | |||
41 | Ensure(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 | |||
50 | Ensure(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 | |||
59 | Ensure(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 | |||
65 | Ensure(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 | |||
74 | Ensure(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 | |||
83 | Ensure(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 | |||
93 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
30 | void signal_data_written(void) { | ||
31 | mock(); | ||
32 | } | ||
33 | |||
34 | static uint8_t sent_data[2048]; | ||
35 | static uint16_t sent_data_size; | ||
36 | |||
37 | void 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 | |||
43 | typedef struct { | ||
44 | uint32_t test; | ||
45 | } test_object1_t; | ||
46 | |||
47 | typedef struct { | ||
48 | uint32_t test1; | ||
49 | uint32_t test2; | ||
50 | } test_object2_t; | ||
51 | |||
52 | MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t); | ||
53 | MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t); | ||
54 | SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t); | ||
55 | |||
56 | static 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 | |||
62 | Describe(Transport); | ||
63 | BeforeEach(Transport) { | ||
64 | add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); | ||
65 | sent_data_size = 0; | ||
66 | } | ||
67 | AfterEach(Transport) {} | ||
68 | |||
69 | Ensure(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 | |||
81 | Ensure(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 | |||
96 | Ensure(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 | |||
112 | Ensure(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 | |||
127 | Ensure(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 | |||
142 | Ensure(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 | |||
156 | Ensure(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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include <cgreen/cgreen.h> | ||
26 | #include "serial_link/protocol/triple_buffered_object.c" | ||
27 | |||
28 | typedef struct { | ||
29 | uint8_t state; | ||
30 | uint32_t buffer[3]; | ||
31 | }test_object_t; | ||
32 | |||
33 | test_object_t test_object; | ||
34 | |||
35 | Describe(TripleBufferedObject); | ||
36 | BeforeEach(TripleBufferedObject) { | ||
37 | triple_buffer_init((triple_buffer_object_t*)&test_object); | ||
38 | } | ||
39 | AfterEach(TripleBufferedObject) {} | ||
40 | |||
41 | |||
42 | Ensure(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 | |||
48 | Ensure(TripleBufferedObject, does_not_read_empty) { | ||
49 | assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); | ||
50 | } | ||
51 | |||
52 | Ensure(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 | |||
60 | Ensure(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 | |||
71 | Ensure(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 | ||
5 | MCU = 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. | ||
18 | F_CPU = 16000000 | ||
19 | |||
20 | |||
21 | # | ||
22 | # LUFA specific | ||
23 | # | ||
24 | # Target architecture (see library "Board Types" documentation). | ||
25 | ARCH = 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. | ||
38 | F_USB = $(F_CPU) | ||
39 | |||
40 | # Interrupt driven control endpoint task(+60) | ||
41 | OPT_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 | ||
50 | OPT_DEFS += -DBOOTLOADER_SIZE=512 | ||
51 | |||
52 | |||
53 | # Build Options | ||
54 | # change yes to no to disable | ||
55 | # | ||
56 | BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) | ||
57 | MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) | ||
58 | EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) | ||
59 | CONSOLE_ENABLE ?= yes # Console for debug(+400) | ||
60 | COMMAND_ENABLE ?= yes # Commands for debug and configuration | ||
61 | # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE | ||
62 | SLEEP_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 | ||
64 | NKRO_ENABLE ?= no # USB Nkey Rollover | ||
65 | BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default | ||
66 | MIDI_ENABLE ?= no # MIDI controls | ||
67 | UNICODE_ENABLE ?= no # Unicode | ||
68 | BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID | ||
69 | AUDIO_ENABLE ?= no # Audio output on port C6 | ||
70 | |||
71 | ifndef QUANTUM_DIR | ||
72 | include ../../Makefile | ||
73 | endif | ||
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 | /* | ||
2 | Copyright 2012 Jun Wako <wakojun@gmail.com> | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along 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 | # | ||
5 | BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) | ||
6 | MOUSEKEY_ENABLE = yes # Mouse keys(+4700) | ||
7 | EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | ||
8 | CONSOLE_ENABLE = no # Console for debug(+400) | ||
9 | COMMAND_ENABLE = yes # Commands for debug and configuration | ||
10 | NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
11 | BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | ||
12 | MIDI_ENABLE = no # MIDI controls | ||
13 | AUDIO_ENABLE = no # Audio output on port C6 | ||
14 | UNICODE_ENABLE = no # Unicode | ||
15 | BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID | ||
16 | RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. | ||
17 | SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend | ||
18 | |||
19 | ifndef QUANTUM_DIR | ||
20 | include ../../../../Makefile | ||
21 | endif \ 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 | |||
3 | const 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 | |||
10 | const uint16_t PROGMEM fn_actions[] = { | ||
11 | |||
12 | }; | ||
13 | |||
14 | const 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 | |||
30 | void matrix_init_user(void) { | ||
31 | |||
32 | } | ||
33 | |||
34 | void matrix_scan_user(void) { | ||
35 | |||
36 | } | ||
37 | |||
38 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
39 | return true; | ||
40 | } | ||
41 | |||
42 | void 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 | |||
6 | For the full Quantum feature list, see [the parent readme.md](/doc/readme.md). | ||
7 | |||
8 | ## Building | ||
9 | |||
10 | Download 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 | |||
12 | Depending on which keymap you would like to use, you will have to compile slightly differently. | ||
13 | |||
14 | ### Default | ||
15 | |||
16 | To build with the default keymap, simply run `make`. | ||
17 | |||
18 | ### Other Keymaps | ||
19 | |||
20 | Several 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 | |||
22 | To 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 | |||
28 | Keymaps 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 | |||
3 | void 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 | |||
10 | void matrix_scan_kb(void) { | ||
11 | // put your looping keyboard code here | ||
12 | // runs every cycle (a lot) | ||
13 | |||
14 | matrix_scan_user(); | ||
15 | } | ||
16 | |||
17 | bool 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 | |||
24 | void 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 @@ | |||
1 | The files in this project are licensed under the MIT license | ||
2 | It uses the following libraries | ||
3 | uGFX - with it's own license, see the license.html file in the uGFX subfolder for more information | ||
4 | tmk_core - is indirectly used and not included in the repository. It's licensed under the GPLv2 license | ||
5 | Chibios - which is used by tmk_core is licensed under GPLv3. | ||
6 | |||
7 | Therefore the effective license for any project using the library is GPLv3 | ||
8 | |||
9 | The MIT License (MIT) | ||
10 | |||
11 | Copyright (c) 2016 Fred Sundvik | ||
12 | |||
13 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
14 | of this software and associated documentation files (the "Software"), to deal | ||
15 | in the Software without restriction, including without limitation the rights | ||
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
17 | copies of the Software, and to permit persons to whom the Software is | ||
18 | furnished to do so, subject to the following conditions: | ||
19 | |||
20 | The above copyright notice and this permission notice shall be included in all | ||
21 | copies or substantial portions of the Software. | ||
22 | |||
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
29 | SOFTWARE. | ||
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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include "keyboard.h" | ||
26 | #include "action_layer.h" | ||
27 | #include "visualizer.h" | ||
28 | #include "host.h" | ||
29 | |||
30 | void post_keyboard_init(void) { | ||
31 | visualizer_init(); | ||
32 | } | ||
33 | |||
34 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
54 | void 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 | |||
86 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
38 | static 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 | ||
42 | bool 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 | ||
64 | static 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 | ||
72 | static 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 | ||
84 | static 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 | |||
91 | void 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 | |||
100 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include "lcd_backlight.h" | ||
26 | #include <math.h> | ||
27 | |||
28 | static uint8_t current_hue = 0x00; | ||
29 | static uint8_t current_saturation = 0x00; | ||
30 | static uint8_t current_intensity = 0xFF; | ||
31 | static uint8_t current_brightness = 0x7F; | ||
32 | |||
33 | void 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 | ||
41 | static 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 | |||
69 | void 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 | |||
82 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
35 | void lcd_backlight_init(void); | ||
36 | void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity); | ||
37 | void lcd_backlight_brightness(uint8_t b); | ||
38 | |||
39 | void lcd_backlight_hal_init(void); | ||
40 | void 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 | |||
3 | This 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 | ||
7 | You 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 | |||
11 | 1. Add tmk_visualizer as a submodule to your project | ||
12 | 1. Set VISUALIZER_DIR in the main keyboard project makefile to point to the submodule | ||
13 | 1. Define LCD\_ENABLE and/or LCD\_BACKLIGHT\_ENABLE, to enable support | ||
14 | 1. Include the visualizer.mk make file | ||
15 | 1. Copy the files in the example\_integration folder to your keyboard project | ||
16 | 1. 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. | ||
17 | 1. Edit the files to match your hardware. You might might want to read the Chibios and UGfx documentation, for more information. | ||
18 | 1. 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | |||
57 | static visualizer_keyboard_status_t current_status = { | ||
58 | .layer = 0xFFFFFFFF, | ||
59 | .default_layer = 0xFFFFFFFF, | ||
60 | .leds = 0xFFFFFFFF, | ||
61 | .suspended = false, | ||
62 | }; | ||
63 | |||
64 | static 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 | |||
71 | static event_source_t layer_changed_event; | ||
72 | static bool visualizer_enabled = false; | ||
73 | |||
74 | #define MAX_SIMULTANEOUS_ANIMATIONS 4 | ||
75 | static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {}; | ||
76 | |||
77 | #ifdef USE_SERIAL_LINK | ||
78 | MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t); | ||
79 | |||
80 | static remote_object_t* remote_objects[] = { | ||
81 | REMOTE_OBJECT(current_status), | ||
82 | }; | ||
83 | |||
84 | #endif | ||
85 | |||
86 | |||
87 | void 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 | |||
105 | void 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 | |||
117 | void 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 | |||
128 | static 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 | |||
175 | bool 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 | ||
182 | bool 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 | |||
215 | bool 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 | ||
228 | bool 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 | |||
236 | static 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 | |||
261 | bool 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 | |||
276 | bool 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 | |||
288 | bool 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 | |||
297 | bool 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 | ||
306 | static THD_WORKING_AREA(visualizerThreadStack, 1024); | ||
307 | static 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, ¤t_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 | |||
402 | void 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 | |||
421 | void 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 | |||
438 | void 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(¤t_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(¤t_status, &new_status)) { | ||
466 | changed = true; | ||
467 | current_status = new_status; | ||
468 | } | ||
469 | } | ||
470 | update_status(changed); | ||
471 | } | ||
472 | |||
473 | void visualizer_suspend(void) { | ||
474 | current_status.suspended = true; | ||
475 | update_status(true); | ||
476 | } | ||
477 | |||
478 | void 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 | /* | ||
2 | The MIT License (MIT) | ||
3 | |||
4 | Copyright (c) 2016 Fred Sundvik | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | of this software and associated documentation files (the "Software"), to deal | ||
8 | in the Software without restriction, including without limitation the rights | ||
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | copies of the Software, and to permit persons to whom the Software is | ||
11 | furnished to do so, subject to the following conditions: | ||
12 | |||
13 | The above copyright notice and this permission notice shall be included in all | ||
14 | copies or substantial portions of the Software. | ||
15 | |||
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
22 | SOFTWARE. | ||
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 | ||
40 | void visualizer_init(void); | ||
41 | // This should be called at every matrix scan | ||
42 | void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds); | ||
43 | // This should be called when the keyboard goes to suspend state | ||
44 | void visualizer_suspend(void); | ||
45 | // This should be called when the keyboard wakes up from suspend state | ||
46 | void 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 | |||
51 | struct keyframe_animation_t; | ||
52 | |||
53 | typedef 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 | ||
63 | typedef 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 | ||
83 | typedef 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 | ||
87 | typedef 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 | |||
102 | void start_keyframe_animation(keyframe_animation_t* animation); | ||
103 | void 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 | ||
107 | bool 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) | ||
109 | bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state); | ||
110 | // Sets the backlight color to the target color | ||
111 | bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state); | ||
112 | // Displays the layer text centered vertically on the screen | ||
113 | bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state); | ||
114 | // Displays a bitmap (0/1) of all the currently active layers | ||
115 | bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state); | ||
116 | |||
117 | bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state); | ||
118 | bool 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) | ||
122 | bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state); | ||
123 | |||
124 | // These two functions have to be implemented by the user | ||
125 | void initialize_user_visualizer(visualizer_state_t* state); | ||
126 | void update_user_visualizer_state(visualizer_state_t* state); | ||
127 | void user_visualizer_suspend(visualizer_state_t* state); | ||
128 | void 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 | |||
23 | GFXLIB = $(VISUALIZER_DIR)/ugfx | ||
24 | ifdef LCD_ENABLE | ||
25 | include $(GFXLIB)/gfx.mk | ||
26 | UDEFS += -DLCD_ENABLE | ||
27 | ULIBS += -lm | ||
28 | endif | ||
29 | SRC += $(GFXSRC) $(VISUALIZER_DIR)/visualizer.c | ||
30 | UINCDIR += $(GFXINC) $(VISUALIZER_DIR) | ||
31 | |||
32 | ifdef LCD_BACKLIGHT_ENABLE | ||
33 | SRC += $(VISUALIZER_DIR)/lcd_backlight.c | ||
34 | SRC += lcd_backlight_hal.c | ||
35 | UDEFS += -DLCD_BACKLIGHT_ENABLE | ||
36 | endif | ||
37 | |||
38 | ifndef VISUALIZER_USER | ||
39 | VISUALIZER_USER = visualizer_user.c | ||
40 | endif | ||
41 | SRC += $(VISUALIZER_USER) \ No newline at end of file | ||