diff options
Diffstat (limited to 'quantum')
110 files changed, 11381 insertions, 1924 deletions
diff --git a/quantum/audio.c b/quantum/audio.c deleted file mode 100644 index 3a3a1a491..000000000 --- a/quantum/audio.c +++ /dev/null | |||
| @@ -1,362 +0,0 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include <math.h> | ||
| 4 | #include <avr/pgmspace.h> | ||
| 5 | #include <avr/interrupt.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | |||
| 8 | #include "audio.h" | ||
| 9 | #include "keymap_common.h" | ||
| 10 | |||
| 11 | #define PI 3.14159265 | ||
| 12 | |||
| 13 | // #define PWM_AUDIO | ||
| 14 | |||
| 15 | #ifdef PWM_AUDIO | ||
| 16 | #include "wave.h" | ||
| 17 | #define SAMPLE_DIVIDER 39 | ||
| 18 | #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048) | ||
| 19 | // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap | ||
| 20 | #endif | ||
| 21 | |||
| 22 | void delay_us(int count) { | ||
| 23 | while(count--) { | ||
| 24 | _delay_us(1); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | int voices = 0; | ||
| 29 | int voice_place = 0; | ||
| 30 | double frequency = 0; | ||
| 31 | int volume = 0; | ||
| 32 | long position = 0; | ||
| 33 | |||
| 34 | double frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 35 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 36 | bool sliding = false; | ||
| 37 | |||
| 38 | int max = 0xFF; | ||
| 39 | float sum = 0; | ||
| 40 | int value = 128; | ||
| 41 | float place = 0; | ||
| 42 | float places[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 43 | |||
| 44 | uint16_t place_int = 0; | ||
| 45 | bool repeat = true; | ||
| 46 | uint8_t * sample; | ||
| 47 | uint16_t sample_length = 0; | ||
| 48 | |||
| 49 | |||
| 50 | bool notes = false; | ||
| 51 | bool note = false; | ||
| 52 | float note_frequency = 0; | ||
| 53 | float note_length = 0; | ||
| 54 | uint16_t note_position = 0; | ||
| 55 | float (* notes_pointer)[][2]; | ||
| 56 | uint8_t notes_length; | ||
| 57 | bool notes_repeat; | ||
| 58 | uint8_t current_note = 0; | ||
| 59 | |||
| 60 | void stop_all_notes() { | ||
| 61 | voices = 0; | ||
| 62 | #ifdef PWM_AUDIO | ||
| 63 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 64 | #else | ||
| 65 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 66 | TCCR3A &= ~_BV(COM3A1); | ||
| 67 | #endif | ||
| 68 | notes = false; | ||
| 69 | note = false; | ||
| 70 | frequency = 0; | ||
| 71 | volume = 0; | ||
| 72 | |||
| 73 | for (int i = 0; i < 8; i++) { | ||
| 74 | frequencies[i] = 0; | ||
| 75 | volumes[i] = 0; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | void stop_note(double freq) { | ||
| 80 | #ifdef PWM_AUDIO | ||
| 81 | freq = freq / SAMPLE_RATE; | ||
| 82 | #endif | ||
| 83 | for (int i = 7; i >= 0; i--) { | ||
| 84 | if (frequencies[i] == freq) { | ||
| 85 | frequencies[i] = 0; | ||
| 86 | volumes[i] = 0; | ||
| 87 | for (int j = i; (j < 7); j++) { | ||
| 88 | frequencies[j] = frequencies[j+1]; | ||
| 89 | frequencies[j+1] = 0; | ||
| 90 | volumes[j] = volumes[j+1]; | ||
| 91 | volumes[j+1] = 0; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } | ||
| 95 | voices--; | ||
| 96 | if (voices < 0) | ||
| 97 | voices = 0; | ||
| 98 | if (voices == 0) { | ||
| 99 | #ifdef PWM_AUDIO | ||
| 100 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 101 | #else | ||
| 102 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 103 | TCCR3A &= ~_BV(COM3A1); | ||
| 104 | #endif | ||
| 105 | frequency = 0; | ||
| 106 | volume = 0; | ||
| 107 | note = false; | ||
| 108 | } else { | ||
| 109 | double freq = frequencies[voices - 1]; | ||
| 110 | int vol = volumes[voices - 1]; | ||
| 111 | double starting_f = frequency; | ||
| 112 | if (frequency < freq) { | ||
| 113 | sliding = true; | ||
| 114 | for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) { | ||
| 115 | frequency = f; | ||
| 116 | } | ||
| 117 | sliding = false; | ||
| 118 | } else if (frequency > freq) { | ||
| 119 | sliding = true; | ||
| 120 | for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) { | ||
| 121 | frequency = f; | ||
| 122 | } | ||
| 123 | sliding = false; | ||
| 124 | } | ||
| 125 | frequency = freq; | ||
| 126 | volume = vol; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | void init_notes() { | ||
| 131 | |||
| 132 | #ifdef PWM_AUDIO | ||
| 133 | PLLFRQ = _BV(PDIV2); | ||
| 134 | PLLCSR = _BV(PLLE); | ||
| 135 | while(!(PLLCSR & _BV(PLOCK))); | ||
| 136 | PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */ | ||
| 137 | |||
| 138 | /* Init a fast PWM on Timer4 */ | ||
| 139 | TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */ | ||
| 140 | TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */ | ||
| 141 | OCR4A = 0; | ||
| 142 | |||
| 143 | /* Enable the OC4A output */ | ||
| 144 | DDRC |= _BV(PORTC6); | ||
| 145 | |||
| 146 | TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs | ||
| 147 | |||
| 148 | TCCR3A = 0x0; // Options not needed | ||
| 149 | TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC | ||
| 150 | OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback | ||
| 151 | #else | ||
| 152 | DDRC |= _BV(PORTC6); | ||
| 153 | |||
| 154 | TIMSK3 &= ~_BV(OCIE3A); // Turn off 3A interputs | ||
| 155 | |||
| 156 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||
| 157 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | ||
| 158 | #endif | ||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 162 | ISR(TIMER3_COMPA_vect) { | ||
| 163 | |||
| 164 | if (note) { | ||
| 165 | #ifdef PWM_AUDIO | ||
| 166 | if (voices == 1) { | ||
| 167 | // SINE | ||
| 168 | OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2; | ||
| 169 | |||
| 170 | // SQUARE | ||
| 171 | // if (((int)place) >= 1024){ | ||
| 172 | // OCR4A = 0xFF >> 2; | ||
| 173 | // } else { | ||
| 174 | // OCR4A = 0x00; | ||
| 175 | // } | ||
| 176 | |||
| 177 | // SAWTOOTH | ||
| 178 | // OCR4A = (int)place / 4; | ||
| 179 | |||
| 180 | // TRIANGLE | ||
| 181 | // if (((int)place) >= 1024) { | ||
| 182 | // OCR4A = (int)place / 2; | ||
| 183 | // } else { | ||
| 184 | // OCR4A = 2048 - (int)place / 2; | ||
| 185 | // } | ||
| 186 | |||
| 187 | place += frequency; | ||
| 188 | |||
| 189 | if (place >= SINE_LENGTH) | ||
| 190 | place -= SINE_LENGTH; | ||
| 191 | |||
| 192 | } else { | ||
| 193 | int sum = 0; | ||
| 194 | for (int i = 0; i < voices; i++) { | ||
| 195 | // SINE | ||
| 196 | sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2; | ||
| 197 | |||
| 198 | // SQUARE | ||
| 199 | // if (((int)places[i]) >= 1024){ | ||
| 200 | // sum += 0xFF >> 2; | ||
| 201 | // } else { | ||
| 202 | // sum += 0x00; | ||
| 203 | // } | ||
| 204 | |||
| 205 | places[i] += frequencies[i]; | ||
| 206 | |||
| 207 | if (places[i] >= SINE_LENGTH) | ||
| 208 | places[i] -= SINE_LENGTH; | ||
| 209 | } | ||
| 210 | OCR4A = sum; | ||
| 211 | } | ||
| 212 | #else | ||
| 213 | if (frequency > 0) { | ||
| 214 | // ICR3 = (int)(((double)F_CPU) / frequency); // Set max to the period | ||
| 215 | // OCR3A = (int)(((double)F_CPU) / frequency) >> 1; // Set compare to half the period | ||
| 216 | if (place > 10) { | ||
| 217 | voice_place = (voice_place + 1) % voices; | ||
| 218 | place = 0.0; | ||
| 219 | } | ||
| 220 | ICR3 = (int)(((double)F_CPU) / frequencies[voice_place]); // Set max to the period | ||
| 221 | OCR3A = (int)(((double)F_CPU) / frequencies[voice_place]) >> 1; // Set compare to half the period | ||
| 222 | place++; | ||
| 223 | } | ||
| 224 | #endif | ||
| 225 | } | ||
| 226 | |||
| 227 | // SAMPLE | ||
| 228 | // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]); | ||
| 229 | |||
| 230 | // place_int++; | ||
| 231 | |||
| 232 | // if (place_int >= sample_length) | ||
| 233 | // if (repeat) | ||
| 234 | // place_int -= sample_length; | ||
| 235 | // else | ||
| 236 | // TIMSK3 &= ~_BV(OCIE3A); | ||
| 237 | |||
| 238 | |||
| 239 | if (notes) { | ||
| 240 | #ifdef PWM_AUDIO | ||
| 241 | OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0; | ||
| 242 | |||
| 243 | place += note_frequency; | ||
| 244 | if (place >= SINE_LENGTH) | ||
| 245 | place -= SINE_LENGTH; | ||
| 246 | #else | ||
| 247 | if (note_frequency > 0) { | ||
| 248 | ICR3 = (int)(((double)F_CPU) / note_frequency); // Set max to the period | ||
| 249 | OCR3A = (int)(((double)F_CPU) / note_frequency) >> 1; // Set compare to half the period | ||
| 250 | } | ||
| 251 | #endif | ||
| 252 | |||
| 253 | |||
| 254 | note_position++; | ||
| 255 | if (note_position >= note_length) { | ||
| 256 | current_note++; | ||
| 257 | if (current_note >= notes_length) { | ||
| 258 | if (notes_repeat) { | ||
| 259 | current_note = 0; | ||
| 260 | } else { | ||
| 261 | #ifdef PWM_AUDIO | ||
| 262 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 263 | #else | ||
| 264 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 265 | TCCR3A &= ~_BV(COM3A1); | ||
| 266 | #endif | ||
| 267 | notes = false; | ||
| 268 | return; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | #ifdef PWM_AUDIO | ||
| 272 | note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||
| 273 | note_length = (*notes_pointer)[current_note][1]; | ||
| 274 | #else | ||
| 275 | note_frequency = (*notes_pointer)[current_note][0]; | ||
| 276 | note_length = (*notes_pointer)[current_note][1] / 4; | ||
| 277 | #endif | ||
| 278 | note_position = 0; | ||
| 279 | } | ||
| 280 | |||
| 281 | } | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | void play_notes(float (*np)[][2], uint8_t n_length, bool n_repeat) { | ||
| 286 | if (note) | ||
| 287 | stop_all_notes(); | ||
| 288 | notes = true; | ||
| 289 | |||
| 290 | notes_pointer = np; | ||
| 291 | notes_length = n_length; | ||
| 292 | notes_repeat = n_repeat; | ||
| 293 | |||
| 294 | place = 0; | ||
| 295 | current_note = 0; | ||
| 296 | #ifdef PWM_AUDIO | ||
| 297 | note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||
| 298 | note_length = (*notes_pointer)[current_note][1]; | ||
| 299 | #else | ||
| 300 | note_frequency = (*notes_pointer)[current_note][0]; | ||
| 301 | note_length = (*notes_pointer)[current_note][1] / 4; | ||
| 302 | #endif | ||
| 303 | note_position = 0; | ||
| 304 | |||
| 305 | |||
| 306 | #ifdef PWM_AUDIO | ||
| 307 | TIMSK3 |= _BV(OCIE3A); | ||
| 308 | #else | ||
| 309 | TIMSK3 |= _BV(OCIE3A); | ||
| 310 | TCCR3A |= _BV(COM3A1); | ||
| 311 | #endif | ||
| 312 | } | ||
| 313 | |||
| 314 | void play_sample(uint8_t * s, uint16_t l, bool r) { | ||
| 315 | stop_all_notes(); | ||
| 316 | place_int = 0; | ||
| 317 | sample = s; | ||
| 318 | sample_length = l; | ||
| 319 | repeat = r; | ||
| 320 | |||
| 321 | #ifdef PWM_AUDIO | ||
| 322 | TIMSK3 |= _BV(OCIE3A); | ||
| 323 | #else | ||
| 324 | #endif | ||
| 325 | } | ||
| 326 | |||
| 327 | void play_note(double freq, int vol) { | ||
| 328 | if (notes) | ||
| 329 | stop_all_notes(); | ||
| 330 | note = true; | ||
| 331 | #ifdef PWM_AUDIO | ||
| 332 | freq = freq / SAMPLE_RATE; | ||
| 333 | #endif | ||
| 334 | if (freq > 0) { | ||
| 335 | if (frequency != 0) { | ||
| 336 | double starting_f = frequency; | ||
| 337 | if (frequency < freq) { | ||
| 338 | for (double f = starting_f; f <= freq; f += ((freq - starting_f) / 2000.0)) { | ||
| 339 | frequency = f; | ||
| 340 | } | ||
| 341 | } else if (frequency > freq) { | ||
| 342 | for (double f = starting_f; f >= freq; f -= ((starting_f - freq) / 2000.0)) { | ||
| 343 | frequency = f; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | } | ||
| 347 | frequency = freq; | ||
| 348 | volume = vol; | ||
| 349 | |||
| 350 | frequencies[voices] = frequency; | ||
| 351 | volumes[voices] = volume; | ||
| 352 | voices++; | ||
| 353 | } | ||
| 354 | |||
| 355 | #ifdef PWM_AUDIO | ||
| 356 | TIMSK3 |= _BV(OCIE3A); | ||
| 357 | #else | ||
| 358 | TIMSK3 |= _BV(OCIE3A); | ||
| 359 | TCCR3A |= _BV(COM3A1); | ||
| 360 | #endif | ||
| 361 | |||
| 362 | } \ No newline at end of file | ||
diff --git a/quantum/audio.h b/quantum/audio.h deleted file mode 100644 index 99203cea7..000000000 --- a/quantum/audio.h +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | #include <stdint.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <avr/io.h> | ||
| 4 | #include <util/delay.h> | ||
| 5 | |||
| 6 | void play_sample(uint8_t * s, uint16_t l, bool r); | ||
| 7 | void play_note(double freq, int vol); | ||
| 8 | void stop_note(double freq); | ||
| 9 | void stop_all_notes(); | ||
| 10 | void init_notes(); | ||
| 11 | void play_notes(float (*np)[][2], uint8_t n_length, bool n_repeat); \ No newline at end of file | ||
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c new file mode 100644 index 000000000..ead5fbf3e --- /dev/null +++ b/quantum/audio/audio.c | |||
| @@ -0,0 +1,477 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | //#include <math.h> | ||
| 4 | #include <avr/pgmspace.h> | ||
| 5 | #include <avr/interrupt.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | #include "print.h" | ||
| 8 | #include "audio.h" | ||
| 9 | #include "keymap.h" | ||
| 10 | |||
| 11 | #include "eeconfig.h" | ||
| 12 | |||
| 13 | #define CPU_PRESCALER 8 | ||
| 14 | |||
| 15 | // ----------------------------------------------------------------------------- | ||
| 16 | // Timer Abstractions | ||
| 17 | // ----------------------------------------------------------------------------- | ||
| 18 | |||
| 19 | // TIMSK3 - Timer/Counter #3 Interrupt Mask Register | ||
| 20 | // Turn on/off 3A interputs, stopping/enabling the ISR calls | ||
| 21 | #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) | ||
| 22 | #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) | ||
| 23 | |||
| 24 | // TCCR3A: Timer/Counter #3 Control Register | ||
| 25 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | ||
| 26 | #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); | ||
| 27 | #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); | ||
| 28 | |||
| 29 | // Fast PWM Mode Controls | ||
| 30 | #define TIMER_3_PERIOD ICR3 | ||
| 31 | #define TIMER_3_DUTY_CYCLE OCR3A | ||
| 32 | |||
| 33 | // ----------------------------------------------------------------------------- | ||
| 34 | |||
| 35 | |||
| 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..8022ca672 --- /dev/null +++ b/quantum/audio/song_list.h | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | #include "musical_notes.h" | ||
| 2 | |||
| 3 | #ifndef SONG_LIST_H | ||
| 4 | #define SONG_LIST_H | ||
| 5 | |||
| 6 | #define ODE_TO_JOY \ | ||
| 7 | Q__NOTE(_E4), Q__NOTE(_E4), Q__NOTE(_F4), Q__NOTE(_G4), \ | ||
| 8 | Q__NOTE(_G4), Q__NOTE(_F4), Q__NOTE(_E4), Q__NOTE(_D4), \ | ||
| 9 | Q__NOTE(_C4), Q__NOTE(_C4), Q__NOTE(_D4), Q__NOTE(_E4), \ | ||
| 10 | QD_NOTE(_E4), E__NOTE(_D4), H__NOTE(_D4), | ||
| 11 | |||
| 12 | #define ROCK_A_BYE_BABY \ | ||
| 13 | QD_NOTE(_B4), E__NOTE(_D4), Q__NOTE(_B5), \ | ||
| 14 | H__NOTE(_A5), Q__NOTE(_G5), \ | ||
| 15 | QD_NOTE(_B4), E__NOTE(_D5), Q__NOTE(_G5), \ | ||
| 16 | H__NOTE(_FS5), | ||
| 17 | |||
| 18 | #define CLOSE_ENCOUNTERS_5_NOTE \ | ||
| 19 | Q__NOTE(_D5), \ | ||
| 20 | Q__NOTE(_E5), \ | ||
| 21 | Q__NOTE(_C5), \ | ||
| 22 | Q__NOTE(_C4), \ | ||
| 23 | Q__NOTE(_G4), | ||
| 24 | |||
| 25 | #define DOE_A_DEER \ | ||
| 26 | QD_NOTE(_C4), E__NOTE(_D4), \ | ||
| 27 | QD_NOTE(_E4), E__NOTE(_C4), \ | ||
| 28 | Q__NOTE(_E4), Q__NOTE(_C4), \ | ||
| 29 | Q__NOTE(_E4), | ||
| 30 | |||
| 31 | /* Requires: PLAY_NOTE_ARRAY(..., ..., STACCATO); */ | ||
| 32 | #define IN_LIKE_FLINT \ | ||
| 33 | E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4), \ | ||
| 34 | E__NOTE(_AS4), E__NOTE(_B4), QD_NOTE(_CS4), \ | ||
| 35 | E__NOTE(_B4), E__NOTE(_CS4), QD_NOTE(_DS4), \ | ||
| 36 | E__NOTE(_CS4), E__NOTE(_B4), QD_NOTE(_AS4), \ | ||
| 37 | E__NOTE(_AS4), E__NOTE(_AS4), QD_NOTE(_B4), | ||
| 38 | |||
| 39 | #define GOODBYE_SOUND \ | ||
| 40 | E__NOTE(_E7), \ | ||
| 41 | E__NOTE(_A6), \ | ||
| 42 | ED_NOTE(_E6), | ||
| 43 | |||
| 44 | #define STARTUP_SOUND \ | ||
| 45 | ED_NOTE(_E7 ), \ | ||
| 46 | E__NOTE(_CS7), \ | ||
| 47 | E__NOTE(_E6 ), \ | ||
| 48 | E__NOTE(_A6 ), \ | ||
| 49 | M__NOTE(_CS7, 20), | ||
| 50 | |||
| 51 | #define QWERTY_SOUND \ | ||
| 52 | E__NOTE(_GS6 ), \ | ||
| 53 | E__NOTE(_A6 ), \ | ||
| 54 | S__NOTE(_REST), \ | ||
| 55 | Q__NOTE(_E7 ), | ||
| 56 | |||
| 57 | #define COLEMAK_SOUND \ | ||
| 58 | E__NOTE(_GS6 ), \ | ||
| 59 | E__NOTE(_A6 ), \ | ||
| 60 | S__NOTE(_REST), \ | ||
| 61 | ED_NOTE(_E7 ), \ | ||
| 62 | S__NOTE(_REST), \ | ||
| 63 | ED_NOTE(_GS7 ), | ||
| 64 | |||
| 65 | #define DVORAK_SOUND \ | ||
| 66 | E__NOTE(_GS6 ), \ | ||
| 67 | E__NOTE(_A6 ), \ | ||
| 68 | S__NOTE(_REST), \ | ||
| 69 | E__NOTE(_E7 ), \ | ||
| 70 | S__NOTE(_REST), \ | ||
| 71 | E__NOTE(_FS7 ), \ | ||
| 72 | S__NOTE(_REST), \ | ||
| 73 | E__NOTE(_E7 ), | ||
| 74 | |||
| 75 | #define PLOVER_SOUND \ | ||
| 76 | E__NOTE(_GS6 ), \ | ||
| 77 | E__NOTE(_A6 ), \ | ||
| 78 | S__NOTE(_REST), \ | ||
| 79 | ED_NOTE(_E7 ), \ | ||
| 80 | S__NOTE(_REST), \ | ||
| 81 | ED_NOTE(_A7 ), | ||
| 82 | |||
| 83 | #define PLOVER_GOODBYE_SOUND \ | ||
| 84 | E__NOTE(_GS6 ), \ | ||
| 85 | E__NOTE(_A6 ), \ | ||
| 86 | S__NOTE(_REST), \ | ||
| 87 | ED_NOTE(_A7 ), \ | ||
| 88 | S__NOTE(_REST), \ | ||
| 89 | ED_NOTE(_E7 ), | ||
| 90 | |||
| 91 | #define MUSIC_SCALE_SOUND \ | ||
| 92 | E__NOTE(_A5 ), \ | ||
| 93 | E__NOTE(_B5 ), \ | ||
| 94 | E__NOTE(_CS6), \ | ||
| 95 | E__NOTE(_D6 ), \ | ||
| 96 | E__NOTE(_E6 ), \ | ||
| 97 | E__NOTE(_FS6), \ | ||
| 98 | E__NOTE(_GS6), \ | ||
| 99 | E__NOTE(_A6 ), | ||
| 100 | |||
| 101 | #define CAPS_LOCK_ON_SOUND \ | ||
| 102 | E__NOTE(_A3), \ | ||
| 103 | E__NOTE(_B3), | ||
| 104 | |||
| 105 | #define CAPS_LOCK_OFF_SOUND \ | ||
| 106 | E__NOTE(_B3), \ | ||
| 107 | E__NOTE(_A3), | ||
| 108 | |||
| 109 | #define SCROLL_LOCK_ON_SOUND \ | ||
| 110 | E__NOTE(_D4), \ | ||
| 111 | E__NOTE(_E4), | ||
| 112 | |||
| 113 | #define SCROLL_LOCK_OFF_SOUND \ | ||
| 114 | E__NOTE(_E4), \ | ||
| 115 | E__NOTE(_D4), | ||
| 116 | |||
| 117 | #define NUM_LOCK_ON_SOUND \ | ||
| 118 | E__NOTE(_D5), \ | ||
| 119 | E__NOTE(_E5), | ||
| 120 | |||
| 121 | #define NUM_LOCK_OFF_SOUND \ | ||
| 122 | E__NOTE(_E5), \ | ||
| 123 | E__NOTE(_D5), | ||
| 124 | |||
| 125 | #endif | ||
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c new file mode 100644 index 000000000..6d4172a06 --- /dev/null +++ b/quantum/audio/voices.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | #include "voices.h" | ||
| 2 | #include "audio.h" | ||
| 3 | #include "stdlib.h" | ||
| 4 | |||
| 5 | // these are imported from audio.c | ||
| 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/wave.h b/quantum/audio/wave.h index 6ebc34851..6ebc34851 100644 --- a/quantum/wave.h +++ b/quantum/audio/wave.h | |||
diff --git a/quantum/config_common.h b/quantum/config_common.h index da53fce89..8ed5f4a10 100644 --- a/quantum/config_common.h +++ b/quantum/config_common.h | |||
| @@ -1,70 +1,83 @@ | |||
| 1 | #ifndef CONFIG_DEFINITIONS_H | 1 | #ifndef CONFIG_DEFINITIONS_H |
| 2 | #define CONFIG_DEFINITIONS_H | 2 | #define CONFIG_DEFINITIONS_H |
| 3 | 3 | ||
| 4 | #define B0 0x20 | 4 | /* diode directions */ |
| 5 | #define B1 0x21 | 5 | #define COL2ROW 0 |
| 6 | #define B2 0x22 | 6 | #define ROW2COL 1 |
| 7 | #define B3 0x23 | 7 | /* I/O pins */ |
| 8 | #define B4 0x24 | 8 | #define B0 0x30 |
| 9 | #define B5 0x25 | 9 | #define B1 0x31 |
| 10 | #define B6 0x26 | 10 | #define B2 0x32 |
| 11 | #define B7 0x27 | 11 | #define B3 0x33 |
| 12 | #define C0 0x30 | 12 | #define B4 0x34 |
| 13 | #define C1 0x31 | 13 | #define B5 0x35 |
| 14 | #define C2 0x32 | 14 | #define B6 0x36 |
| 15 | #define C3 0x33 | 15 | #define B7 0x37 |
| 16 | #define C4 0x34 | 16 | #define C0 0x60 |
| 17 | #define C5 0x35 | 17 | #define C1 0x61 |
| 18 | #define C6 0x36 | 18 | #define C2 0x62 |
| 19 | #define C7 0x37 | 19 | #define C3 0x63 |
| 20 | #define D0 0x40 | 20 | #define C4 0x64 |
| 21 | #define D1 0x41 | 21 | #define C5 0x65 |
| 22 | #define D2 0x42 | 22 | #define C6 0x66 |
| 23 | #define D3 0x43 | 23 | #define C7 0x67 |
| 24 | #define D4 0x44 | 24 | #define D0 0x90 |
| 25 | #define D5 0x45 | 25 | #define D1 0x91 |
| 26 | #define D6 0x46 | 26 | #define D2 0x92 |
| 27 | #define D7 0x47 | 27 | #define D3 0x93 |
| 28 | #define E0 0x50 | 28 | #define D4 0x94 |
| 29 | #define E1 0x51 | 29 | #define D5 0x95 |
| 30 | #define E2 0x52 | 30 | #define D6 0x96 |
| 31 | #define E3 0x53 | 31 | #define D7 0x97 |
| 32 | #define E4 0x54 | 32 | #define E0 0xC0 |
| 33 | #define E5 0x55 | 33 | #define E1 0xC1 |
| 34 | #define E6 0x56 | 34 | #define E2 0xC2 |
| 35 | #define E7 0x57 | 35 | #define E3 0xC3 |
| 36 | #define F0 0x60 | 36 | #define E4 0xC4 |
| 37 | #define F1 0x61 | 37 | #define E5 0xC5 |
| 38 | #define F2 0x62 | 38 | #define E6 0xC6 |
| 39 | #define F3 0x63 | 39 | #define E7 0xC7 |
| 40 | #define F4 0x64 | 40 | #define F0 0xF0 |
| 41 | #define F5 0x65 | 41 | #define F1 0xF1 |
| 42 | #define F6 0x66 | 42 | #define F2 0xF2 |
| 43 | #define F7 0x67 | 43 | #define F3 0xF3 |
| 44 | #define F4 0xF4 | ||
| 45 | #define F5 0xF5 | ||
| 46 | #define F6 0xF6 | ||
| 47 | #define F7 0xF7 | ||
| 48 | #define A0 0x00 | ||
| 49 | #define A1 0x01 | ||
| 50 | #define A2 0x02 | ||
| 51 | #define A3 0x03 | ||
| 52 | #define A4 0x04 | ||
| 53 | #define A5 0x05 | ||
| 54 | #define A6 0x06 | ||
| 55 | #define A7 0x07 | ||
| 44 | 56 | ||
| 45 | #define COL2ROW 0x0 | ||
| 46 | #define ROW2COL 0x1 | ||
| 47 | 57 | ||
| 58 | /* USART configuration */ | ||
| 48 | #ifdef BLUETOOTH_ENABLE | 59 | #ifdef BLUETOOTH_ENABLE |
| 49 | #ifdef __AVR_ATmega32U4__ | 60 | # ifdef __AVR_ATmega32U4__ |
| 50 | #define SERIAL_UART_BAUD 9600 | 61 | # define SERIAL_UART_BAUD 9600 |
| 51 | #define SERIAL_UART_DATA UDR1 | 62 | # define SERIAL_UART_DATA UDR1 |
| 52 | #define SERIAL_UART_UBRR ((F_CPU/(16UL*SERIAL_UART_BAUD))-1) | 63 | # define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1) |
| 53 | #define SERIAL_UART_RXD_VECT USART1_RX_vect | 64 | # define SERIAL_UART_RXD_VECT USART1_RX_vect |
| 54 | #define SERIAL_UART_TXD_READY (UCSR1A&(1<<UDRE1)) | 65 | # define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1)) |
| 55 | #define SERIAL_UART_INIT() do { \ | 66 | # define SERIAL_UART_INIT() do { \ |
| 56 | UBRR1L = (uint8_t) SERIAL_UART_UBRR; /* baud rate */ \ | 67 | /* baud rate */ \ |
| 57 | UBRR1H = (uint8_t) (SERIAL_UART_UBRR>>8); /* baud rate */ \ | 68 | UBRR1L = SERIAL_UART_UBRR; \ |
| 58 | UCSR1B = (1<<TXEN1); /* TX: enable */ \ | 69 | /* baud rate */ \ |
| 59 | UCSR1C = (0<<UPM11) | (0<<UPM10) | /* parity: none(00), even(01), odd(11) */ \ | 70 | UBRR1H = SERIAL_UART_UBRR >> 8; \ |
| 60 | (0<<UCSZ12) | (1<<UCSZ11) | (1<<UCSZ10); /* data-8bit(011) */ \ | 71 | /* enable TX */ \ |
| 61 | sei(); \ | 72 | UCSR1B = _BV(TXEN1); \ |
| 62 | } while(0) | 73 | /* 8-bit data */ \ |
| 63 | #else | 74 | UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \ |
| 64 | # error "USART configuration is needed." | 75 | sei(); \ |
| 76 | } while(0) | ||
| 77 | # else | ||
| 78 | # error "USART configuration is needed." | ||
| 65 | #endif | 79 | #endif |
| 66 | 80 | ||
| 67 | |||
| 68 | // I'm fairly sure these aren't needed, but oh well - Jack | 81 | // I'm fairly sure these aren't needed, but oh well - Jack |
| 69 | 82 | ||
| 70 | /* | 83 | /* |
| @@ -113,4 +126,3 @@ | |||
| 113 | #endif | 126 | #endif |
| 114 | 127 | ||
| 115 | #endif | 128 | #endif |
| 116 | |||
diff --git a/quantum/dynamic_macro.h b/quantum/dynamic_macro.h new file mode 100644 index 000000000..e6dbc5b9c --- /dev/null +++ b/quantum/dynamic_macro.h | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | /* Author: Wojciech Siewierski < wojciech dot siewierski at onet dot pl > */ | ||
| 2 | #ifndef DYNAMIC_MACROS_H | ||
| 3 | #define DYNAMIC_MACROS_H | ||
| 4 | |||
| 5 | #include "action_layer.h" | ||
| 6 | |||
| 7 | #ifndef DYNAMIC_MACRO_SIZE | ||
| 8 | /* May be overridden with a custom value. Be aware that the effective | ||
| 9 | * macro length is half of this value: each keypress is recorded twice | ||
| 10 | * because of the down-event and up-event. This is not a bug, it's the | ||
| 11 | * intended behavior. | ||
| 12 | * | ||
| 13 | * Usually it should be fine to set the macro size to at least 256 but | ||
| 14 | * there have been reports of it being too much in some users' cases, | ||
| 15 | * so 128 is considered a safe default. | ||
| 16 | */ | ||
| 17 | #define DYNAMIC_MACRO_SIZE 128 | ||
| 18 | #endif | ||
| 19 | |||
| 20 | /* DYNAMIC_MACRO_RANGE must be set as the last element of user's | ||
| 21 | * "planck_keycodes" enum prior to including this header. This allows | ||
| 22 | * us to 'extend' it. | ||
| 23 | */ | ||
| 24 | enum dynamic_macro_keycodes { | ||
| 25 | DYN_REC_START1 = DYNAMIC_MACRO_RANGE, | ||
| 26 | DYN_REC_START2, | ||
| 27 | DYN_MACRO_PLAY1, | ||
| 28 | DYN_MACRO_PLAY2, | ||
| 29 | }; | ||
| 30 | |||
| 31 | /* Blink the LEDs to notify the user about some event. */ | ||
| 32 | void dynamic_macro_led_blink(void) | ||
| 33 | { | ||
| 34 | backlight_toggle(); | ||
| 35 | _delay_ms(100); | ||
| 36 | backlight_toggle(); | ||
| 37 | } | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Start recording of the dynamic macro. | ||
| 41 | * | ||
| 42 | * @param[out] macro_pointer The new macro buffer iterator. | ||
| 43 | * @param[in] macro_buffer The macro buffer used to initialize macro_pointer. | ||
| 44 | */ | ||
| 45 | void dynamic_macro_record_start( | ||
| 46 | keyrecord_t **macro_pointer, keyrecord_t *macro_buffer) | ||
| 47 | { | ||
| 48 | dynamic_macro_led_blink(); | ||
| 49 | |||
| 50 | clear_keyboard(); | ||
| 51 | layer_clear(); | ||
| 52 | *macro_pointer = macro_buffer; | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Play the dynamic macro. | ||
| 57 | * | ||
| 58 | * @param macro_buffer[in] The beginning of the macro buffer being played. | ||
| 59 | * @param macro_end[in] The element after the last macro buffer element. | ||
| 60 | * @param direction[in] Either +1 or -1, which way to iterate the buffer. | ||
| 61 | */ | ||
| 62 | void dynamic_macro_play( | ||
| 63 | keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) | ||
| 64 | { | ||
| 65 | uint32_t saved_layer_state = layer_state; | ||
| 66 | |||
| 67 | clear_keyboard(); | ||
| 68 | layer_clear(); | ||
| 69 | |||
| 70 | while (macro_buffer != macro_end) { | ||
| 71 | process_record(macro_buffer); | ||
| 72 | macro_buffer += direction; | ||
| 73 | } | ||
| 74 | |||
| 75 | clear_keyboard(); | ||
| 76 | |||
| 77 | layer_state = saved_layer_state; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Record a single key in a dynamic macro. | ||
| 82 | * | ||
| 83 | * @param macro_pointer[in,out] The current buffer position. | ||
| 84 | * @param macro_end2[in] The end of the other macro which shouldn't be overwritten. | ||
| 85 | * @param direction[in] Either +1 or -1, which way to iterate the buffer. | ||
| 86 | * @param record[in] The current keypress. | ||
| 87 | */ | ||
| 88 | void dynamic_macro_record_key( | ||
| 89 | keyrecord_t **macro_pointer, | ||
| 90 | keyrecord_t *macro_end2, | ||
| 91 | int8_t direction, | ||
| 92 | keyrecord_t *record) | ||
| 93 | { | ||
| 94 | if (*macro_pointer + direction != macro_end2) { | ||
| 95 | **macro_pointer = *record; | ||
| 96 | *macro_pointer += direction; | ||
| 97 | } else { | ||
| 98 | /* Notify about the end of buffer. The blinks are paired | ||
| 99 | * because they should happen on both down and up events. */ | ||
| 100 | backlight_toggle(); | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * End recording of the dynamic macro. Essentially just update the | ||
| 106 | * pointer to the end of the macro. | ||
| 107 | */ | ||
| 108 | void dynamic_macro_record_end(keyrecord_t *macro_pointer, keyrecord_t **macro_end) | ||
| 109 | { | ||
| 110 | dynamic_macro_led_blink(); | ||
| 111 | |||
| 112 | *macro_end = macro_pointer; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* Handle the key events related to the dynamic macros. Should be | ||
| 116 | * called from process_record_user() like this: | ||
| 117 | * | ||
| 118 | * bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
| 119 | * if (!process_record_dynamic_macro(keycode, record)) { | ||
| 120 | * return false; | ||
| 121 | * } | ||
| 122 | * <...THE REST OF THE FUNCTION...> | ||
| 123 | * } | ||
| 124 | */ | ||
| 125 | bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) | ||
| 126 | { | ||
| 127 | /* Both macros use the same buffer but read/write on different | ||
| 128 | * ends of it. | ||
| 129 | * | ||
| 130 | * Macro1 is written left-to-right starting from the beginning of | ||
| 131 | * the buffer. | ||
| 132 | * | ||
| 133 | * Macro2 is written right-to-left starting from the end of the | ||
| 134 | * buffer. | ||
| 135 | * | ||
| 136 | * ¯o_buffer macro_end | ||
| 137 | * v v | ||
| 138 | * +------------------------------------------------------------+ | ||
| 139 | * |>>>>>> MACRO1 >>>>>>| |<<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| | ||
| 140 | * +------------------------------------------------------------+ | ||
| 141 | * ^ ^ | ||
| 142 | * r_macro_end r_macro_buffer | ||
| 143 | * | ||
| 144 | * During the recording when one macro encounters the end of the | ||
| 145 | * other macro, the recording is stopped. Apart from this, there | ||
| 146 | * are no arbitrary limits for the macros' length in relation to | ||
| 147 | * each other: for example one can either have two medium sized | ||
| 148 | * macros or one long macro and one short macro. Or even one empty | ||
| 149 | * and one using the whole buffer. | ||
| 150 | */ | ||
| 151 | static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE]; | ||
| 152 | |||
| 153 | /* Pointer to the first buffer element after the first macro. | ||
| 154 | * Initially points to the very beginning of the buffer since the | ||
| 155 | * macro is empty. */ | ||
| 156 | static keyrecord_t *macro_end = macro_buffer; | ||
| 157 | |||
| 158 | /* The other end of the macro buffer. Serves as the beginning of | ||
| 159 | * the second macro. */ | ||
| 160 | static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1; | ||
| 161 | |||
| 162 | /* Like macro_end but for the second macro. */ | ||
| 163 | static keyrecord_t *r_macro_end = r_macro_buffer; | ||
| 164 | |||
| 165 | /* A persistent pointer to the current macro position (iterator) | ||
| 166 | * used during the recording. */ | ||
| 167 | static keyrecord_t *macro_pointer = NULL; | ||
| 168 | |||
| 169 | /* 0 - no macro is being recorded right now | ||
| 170 | * 1,2 - either macro 1 or 2 is being recorded */ | ||
| 171 | static uint8_t macro_id = 0; | ||
| 172 | |||
| 173 | if (macro_id == 0) { | ||
| 174 | /* No macro recording in progress. */ | ||
| 175 | if (!record->event.pressed) { | ||
| 176 | switch (keycode) { | ||
| 177 | case DYN_REC_START1: | ||
| 178 | dynamic_macro_record_start(¯o_pointer, macro_buffer); | ||
| 179 | macro_id = 1; | ||
| 180 | return false; | ||
| 181 | case DYN_REC_START2: | ||
| 182 | dynamic_macro_record_start(¯o_pointer, r_macro_buffer); | ||
| 183 | macro_id = 2; | ||
| 184 | return false; | ||
| 185 | case DYN_MACRO_PLAY1: | ||
| 186 | dynamic_macro_play(macro_buffer, macro_end, +1); | ||
| 187 | return false; | ||
| 188 | case DYN_MACRO_PLAY2: | ||
| 189 | dynamic_macro_play(r_macro_buffer, r_macro_end, -1); | ||
| 190 | return false; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | } else { | ||
| 194 | /* A macro is being recorded right now. */ | ||
| 195 | switch (keycode) { | ||
| 196 | case MO(_DYN): | ||
| 197 | /* Use the layer key used to access the macro recording as | ||
| 198 | * a stop button. */ | ||
| 199 | if (record->event.pressed) { /* Ignore the initial release | ||
| 200 | * just after the recoding | ||
| 201 | * starts. */ | ||
| 202 | switch (macro_id) { | ||
| 203 | case 1: | ||
| 204 | dynamic_macro_record_end(macro_pointer, ¯o_end); | ||
| 205 | break; | ||
| 206 | case 2: | ||
| 207 | dynamic_macro_record_end(macro_pointer, &r_macro_end); | ||
| 208 | break; | ||
| 209 | } | ||
| 210 | macro_id = 0; | ||
| 211 | } | ||
| 212 | return false; | ||
| 213 | default: | ||
| 214 | /* Store the key in the macro buffer and process it normally. */ | ||
| 215 | switch (macro_id) { | ||
| 216 | case 1: | ||
| 217 | dynamic_macro_record_key(¯o_pointer, r_macro_end, +1, record); | ||
| 218 | break; | ||
| 219 | case 2: | ||
| 220 | dynamic_macro_record_key(¯o_pointer, macro_end, -1, record); | ||
| 221 | break; | ||
| 222 | } | ||
| 223 | return true; | ||
| 224 | break; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | return true; | ||
| 229 | } | ||
| 230 | |||
| 231 | #endif | ||
diff --git a/quantum/keycode_config.c b/quantum/keycode_config.c new file mode 100644 index 000000000..6d90781a1 --- /dev/null +++ b/quantum/keycode_config.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #include "keycode_config.h" | ||
| 2 | |||
| 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..c15b0d32f --- /dev/null +++ b/quantum/keycode_config.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #include "eeconfig.h" | ||
| 2 | #include "keycode.h" | ||
| 3 | |||
| 4 | #ifndef KEYCODE_CONFIG_H | ||
| 5 | #define KEYCODE_CONFIG_H | ||
| 6 | |||
| 7 | uint16_t keycode_config(uint16_t keycode); | ||
| 8 | |||
| 9 | /* NOTE: Not portable. Bit field order depends on implementation */ | ||
| 10 | typedef union { | ||
| 11 | uint16_t raw; | ||
| 12 | struct { | ||
| 13 | bool swap_control_capslock:1; | ||
| 14 | bool capslock_to_control:1; | ||
| 15 | bool swap_lalt_lgui:1; | ||
| 16 | bool swap_ralt_rgui:1; | ||
| 17 | bool no_gui:1; | ||
| 18 | bool swap_grave_esc:1; | ||
| 19 | bool swap_backslash_backspace:1; | ||
| 20 | bool nkro:1; | ||
| 21 | }; | ||
| 22 | } keymap_config_t; | ||
| 23 | |||
| 24 | extern keymap_config_t keymap_config; | ||
| 25 | |||
| 26 | #endif /* KEYCODE_CONFIG_H */ | ||
diff --git a/quantum/keymap.h b/quantum/keymap.h new file mode 100644 index 000000000..a01bbfbd1 --- /dev/null +++ b/quantum/keymap.h | |||
| @@ -0,0 +1,350 @@ | |||
| 1 | /* | ||
| 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 UNICODEMAP_ENABLE | ||
| 88 | QK_UNICODE_MAP = 0x7800, | ||
| 89 | QK_UNICODE_MAP_MAX = 0x7FFF, | ||
| 90 | #endif | ||
| 91 | #ifdef UNICODE_ENABLE | ||
| 92 | QK_UNICODE = 0x8000, | ||
| 93 | QK_UNICODE_MAX = 0xFFFF, | ||
| 94 | #endif | ||
| 95 | |||
| 96 | // Loose keycodes - to be used directly | ||
| 97 | |||
| 98 | RESET = 0x7000, | ||
| 99 | DEBUG, | ||
| 100 | MAGIC_SWAP_CONTROL_CAPSLOCK, | ||
| 101 | MAGIC_CAPSLOCK_TO_CONTROL, | ||
| 102 | MAGIC_SWAP_LALT_LGUI, | ||
| 103 | MAGIC_SWAP_RALT_RGUI, | ||
| 104 | MAGIC_NO_GUI, | ||
| 105 | MAGIC_SWAP_GRAVE_ESC, | ||
| 106 | MAGIC_SWAP_BACKSLASH_BACKSPACE, | ||
| 107 | MAGIC_HOST_NKRO, | ||
| 108 | MAGIC_SWAP_ALT_GUI, | ||
| 109 | MAGIC_UNSWAP_CONTROL_CAPSLOCK, | ||
| 110 | MAGIC_UNCAPSLOCK_TO_CONTROL, | ||
| 111 | MAGIC_UNSWAP_LALT_LGUI, | ||
| 112 | MAGIC_UNSWAP_RALT_RGUI, | ||
| 113 | MAGIC_UNNO_GUI, | ||
| 114 | MAGIC_UNSWAP_GRAVE_ESC, | ||
| 115 | MAGIC_UNSWAP_BACKSLASH_BACKSPACE, | ||
| 116 | MAGIC_UNHOST_NKRO, | ||
| 117 | MAGIC_UNSWAP_ALT_GUI, | ||
| 118 | MAGIC_TOGGLE_NKRO, | ||
| 119 | |||
| 120 | // Leader key | ||
| 121 | #ifndef DISABLE_LEADER | ||
| 122 | KC_LEAD, | ||
| 123 | #endif | ||
| 124 | |||
| 125 | // Audio on/off/toggle | ||
| 126 | AU_ON, | ||
| 127 | AU_OFF, | ||
| 128 | AU_TOG, | ||
| 129 | |||
| 130 | // Music mode on/off/toggle | ||
| 131 | MU_ON, | ||
| 132 | MU_OFF, | ||
| 133 | MU_TOG, | ||
| 134 | |||
| 135 | // Music voice iterate | ||
| 136 | MUV_IN, | ||
| 137 | MUV_DE, | ||
| 138 | |||
| 139 | // Midi mode on/off | ||
| 140 | MIDI_ON, | ||
| 141 | MIDI_OFF, | ||
| 142 | |||
| 143 | // Backlight functionality | ||
| 144 | BL_0, | ||
| 145 | BL_1, | ||
| 146 | BL_2, | ||
| 147 | BL_3, | ||
| 148 | BL_4, | ||
| 149 | BL_5, | ||
| 150 | BL_6, | ||
| 151 | BL_7, | ||
| 152 | BL_8, | ||
| 153 | BL_9, | ||
| 154 | BL_10, | ||
| 155 | BL_11, | ||
| 156 | BL_12, | ||
| 157 | BL_13, | ||
| 158 | BL_14, | ||
| 159 | BL_15, | ||
| 160 | BL_DEC, | ||
| 161 | BL_INC, | ||
| 162 | BL_TOGG, | ||
| 163 | BL_STEP, | ||
| 164 | |||
| 165 | // RGB functionality | ||
| 166 | RGB_TOG, | ||
| 167 | RGB_MOD, | ||
| 168 | RGB_HUI, | ||
| 169 | RGB_HUD, | ||
| 170 | RGB_SAI, | ||
| 171 | RGB_SAD, | ||
| 172 | RGB_VAI, | ||
| 173 | RGB_VAD, | ||
| 174 | |||
| 175 | // Left shift, open paren | ||
| 176 | KC_LSPO, | ||
| 177 | |||
| 178 | // Right shift, close paren | ||
| 179 | KC_RSPC, | ||
| 180 | |||
| 181 | // always leave at the end | ||
| 182 | SAFE_RANGE | ||
| 183 | }; | ||
| 184 | |||
| 185 | // Ability to use mods in layouts | ||
| 186 | #define LCTL(kc) (kc | QK_LCTL) | ||
| 187 | #define LSFT(kc) (kc | QK_LSFT) | ||
| 188 | #define LALT(kc) (kc | QK_LALT) | ||
| 189 | #define LGUI(kc) (kc | QK_LGUI) | ||
| 190 | #define RCTL(kc) (kc | QK_RCTL) | ||
| 191 | #define RSFT(kc) (kc | QK_RSFT) | ||
| 192 | #define RALT(kc) (kc | QK_RALT) | ||
| 193 | #define RGUI(kc) (kc | QK_RGUI) | ||
| 194 | |||
| 195 | #define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI) | ||
| 196 | #define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT) | ||
| 197 | #define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI) | ||
| 198 | #define ALTG(kc) (kc | QK_RCTL | QK_RALT) | ||
| 199 | |||
| 200 | #define MOD_HYPR 0xf | ||
| 201 | #define MOD_MEH 0x7 | ||
| 202 | |||
| 203 | |||
| 204 | // Aliases for shifted symbols | ||
| 205 | // Each key has a 4-letter code, and some have longer aliases too. | ||
| 206 | // While the long aliases are descriptive, the 4-letter codes | ||
| 207 | // make for nicer grid layouts (everything lines up), and are | ||
| 208 | // the preferred style for Quantum. | ||
| 209 | #define KC_TILD LSFT(KC_GRV) // ~ | ||
| 210 | #define KC_TILDE KC_TILD | ||
| 211 | |||
| 212 | #define KC_EXLM LSFT(KC_1) // ! | ||
| 213 | #define KC_EXCLAIM KC_EXLM | ||
| 214 | |||
| 215 | #define KC_AT LSFT(KC_2) // @ | ||
| 216 | |||
| 217 | #define KC_HASH LSFT(KC_3) // # | ||
| 218 | |||
| 219 | #define KC_DLR LSFT(KC_4) // $ | ||
| 220 | #define KC_DOLLAR KC_DLR | ||
| 221 | |||
| 222 | #define KC_PERC LSFT(KC_5) // % | ||
| 223 | #define KC_PERCENT KC_PERC | ||
| 224 | |||
| 225 | #define KC_CIRC LSFT(KC_6) // ^ | ||
| 226 | #define KC_CIRCUMFLEX KC_CIRC | ||
| 227 | |||
| 228 | #define KC_AMPR LSFT(KC_7) // & | ||
| 229 | #define KC_AMPERSAND KC_AMPR | ||
| 230 | |||
| 231 | #define KC_ASTR LSFT(KC_8) // * | ||
| 232 | #define KC_ASTERISK KC_ASTR | ||
| 233 | |||
| 234 | #define KC_LPRN LSFT(KC_9) // ( | ||
| 235 | #define KC_LEFT_PAREN KC_LPRN | ||
| 236 | |||
| 237 | #define KC_RPRN LSFT(KC_0) // ) | ||
| 238 | #define KC_RIGHT_PAREN KC_RPRN | ||
| 239 | |||
| 240 | #define KC_UNDS LSFT(KC_MINS) // _ | ||
| 241 | #define KC_UNDERSCORE KC_UNDS | ||
| 242 | |||
| 243 | #define KC_PLUS LSFT(KC_EQL) // + | ||
| 244 | |||
| 245 | #define KC_LCBR LSFT(KC_LBRC) // { | ||
| 246 | #define KC_LEFT_CURLY_BRACE KC_LCBR | ||
| 247 | |||
| 248 | #define KC_RCBR LSFT(KC_RBRC) // } | ||
| 249 | #define KC_RIGHT_CURLY_BRACE KC_RCBR | ||
| 250 | |||
| 251 | #define KC_LABK LSFT(KC_COMM) // < | ||
| 252 | #define KC_LEFT_ANGLE_BRACKET KC_LABK | ||
| 253 | |||
| 254 | #define KC_RABK LSFT(KC_DOT) // > | ||
| 255 | #define KC_RIGHT_ANGLE_BRACKET KC_RABK | ||
| 256 | |||
| 257 | #define KC_COLN LSFT(KC_SCLN) // : | ||
| 258 | #define KC_COLON KC_COLN | ||
| 259 | |||
| 260 | #define KC_PIPE LSFT(KC_BSLS) // | | ||
| 261 | |||
| 262 | #define KC_LT LSFT(KC_COMM) // < | ||
| 263 | |||
| 264 | #define KC_GT LSFT(KC_DOT) // > | ||
| 265 | |||
| 266 | #define KC_QUES LSFT(KC_SLSH) // ? | ||
| 267 | #define KC_QUESTION KC_QUES | ||
| 268 | |||
| 269 | #define KC_DQT LSFT(KC_QUOT) // " | ||
| 270 | #define KC_DOUBLE_QUOTE KC_DQT | ||
| 271 | #define KC_DQUO KC_DQT | ||
| 272 | |||
| 273 | #define KC_DELT KC_DELETE // Del key (four letter code) | ||
| 274 | |||
| 275 | // Alias for function layers than expand past FN31 | ||
| 276 | #define FUNC(kc) (kc | QK_FUNCTION) | ||
| 277 | |||
| 278 | // Aliases | ||
| 279 | #define S(kc) LSFT(kc) | ||
| 280 | #define F(kc) FUNC(kc) | ||
| 281 | |||
| 282 | #define M(kc) (kc | QK_MACRO) | ||
| 283 | |||
| 284 | #define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE) | ||
| 285 | |||
| 286 | // L-ayer, T-ap - 256 keycode max, 16 layer max | ||
| 287 | #define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8)) | ||
| 288 | |||
| 289 | #define AG_SWAP MAGIC_SWAP_ALT_GUI | ||
| 290 | #define AG_NORM MAGIC_UNSWAP_ALT_GUI | ||
| 291 | |||
| 292 | #define BL_ON BL_9 | ||
| 293 | #define BL_OFF BL_0 | ||
| 294 | |||
| 295 | #define MI_ON MIDI_ON | ||
| 296 | #define MI_OFF MIDI_OFF | ||
| 297 | |||
| 298 | // GOTO layer - 16 layers max | ||
| 299 | // when: | ||
| 300 | // ON_PRESS = 1 | ||
| 301 | // ON_RELEASE = 2 | ||
| 302 | // Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default. | ||
| 303 | // In fact, we changed it to assume ON_PRESS for sanity/simplicity. If needed, you can add your own | ||
| 304 | // keycode modeled after the old version, kept below for this. | ||
| 305 | /* #define TO(layer, when) (layer | QK_TO | (when << 0x4)) */ | ||
| 306 | #define TO(layer) (layer | QK_TO | (ON_PRESS << 0x4)) | ||
| 307 | |||
| 308 | // Momentary switch layer - 256 layer max | ||
| 309 | #define MO(layer) (layer | QK_MOMENTARY) | ||
| 310 | |||
| 311 | // Set default layer - 256 layer max | ||
| 312 | #define DF(layer) (layer | QK_DEF_LAYER) | ||
| 313 | |||
| 314 | // Toggle to layer - 256 layer max | ||
| 315 | #define TG(layer) (layer | QK_TOGGLE_LAYER) | ||
| 316 | |||
| 317 | // One-shot layer - 256 layer max | ||
| 318 | #define OSL(layer) (layer | QK_ONE_SHOT_LAYER) | ||
| 319 | |||
| 320 | // One-shot mod | ||
| 321 | #define OSM(mod) (mod | QK_ONE_SHOT_MOD) | ||
| 322 | |||
| 323 | // M-od, T-ap - 256 keycode max | ||
| 324 | #define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8)) | ||
| 325 | #define CTL_T(kc) MT(MOD_LCTL, kc) | ||
| 326 | #define SFT_T(kc) MT(MOD_LSFT, kc) | ||
| 327 | #define ALT_T(kc) MT(MOD_LALT, kc) | ||
| 328 | #define GUI_T(kc) MT(MOD_LGUI, kc) | ||
| 329 | #define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal | ||
| 330 | #define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl | ||
| 331 | #define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui | ||
| 332 | #define ALL_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI), kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/ | ||
| 333 | |||
| 334 | // Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap | ||
| 335 | #define KC_HYPR HYPR(KC_NO) | ||
| 336 | #define KC_MEH MEH(KC_NO) | ||
| 337 | |||
| 338 | #ifdef UNICODE_ENABLE | ||
| 339 | // For sending unicode codes. | ||
| 340 | // You may not send codes over 7FFF -- this supports most of UTF8. | ||
| 341 | // To have a key that sends out Œ, go UC(0x0152) | ||
| 342 | #define UNICODE(n) (n | QK_UNICODE) | ||
| 343 | #define UC(n) UNICODE(n) | ||
| 344 | #endif | ||
| 345 | |||
| 346 | #ifdef UNICODEMAP_ENABLE | ||
| 347 | #define X(n) (n | QK_UNICODE_MAP) | ||
| 348 | #endif | ||
| 349 | |||
| 350 | #endif | ||
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c index ae109da16..833e5a8f8 100644 --- a/quantum/keymap_common.c +++ b/quantum/keymap_common.c | |||
| @@ -15,236 +15,46 @@ You should have received a copy of the GNU General Public License | |||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include "keymap_common.h" | 18 | #include "keymap.h" |
| 19 | #include "report.h" | 19 | #include "report.h" |
| 20 | #include "keycode.h" | 20 | #include "keycode.h" |
| 21 | #include "action_layer.h" | 21 | #include "action_layer.h" |
| 22 | #if defined(__AVR__) | ||
| 22 | #include <util/delay.h> | 23 | #include <util/delay.h> |
| 24 | #include <stdio.h> | ||
| 25 | #endif | ||
| 23 | #include "action.h" | 26 | #include "action.h" |
| 24 | #include "action_macro.h" | 27 | #include "action_macro.h" |
| 25 | #include "debug.h" | 28 | #include "debug.h" |
| 26 | #include "backlight.h" | 29 | #include "backlight.h" |
| 27 | #include "keymap_midi.h" | 30 | #include "quantum.h" |
| 28 | |||
| 29 | #include <stdio.h> | ||
| 30 | #include <inttypes.h> | ||
| 31 | #ifdef AUDIO_ENABLE | ||
| 32 | #include "audio.h" | ||
| 33 | 31 | ||
| 34 | float goodbye[][2] = { | 32 | #ifdef MIDI_ENABLE |
| 35 | {440.0*pow(2.0,(67)/12.0), 400}, | 33 | #include "process_midi.h" |
| 36 | {0, 50}, | ||
| 37 | {440.0*pow(2.0,(60)/12.0), 400}, | ||
| 38 | {0, 50}, | ||
| 39 | {440.0*pow(2.0,(55)/12.0), 600}, | ||
| 40 | }; | ||
| 41 | #endif | 34 | #endif |
| 42 | 35 | ||
| 43 | static action_t keycode_to_action(uint16_t keycode); | 36 | extern keymap_config_t keymap_config; |
| 37 | |||
| 38 | #include <inttypes.h> | ||
| 44 | 39 | ||
| 45 | /* converts key to action */ | 40 | /* converts key to action */ |
| 46 | action_t action_for_key(uint8_t layer, keypos_t key) | 41 | action_t action_for_key(uint8_t layer, keypos_t key) |
| 47 | { | 42 | { |
| 48 | // 16bit keycodes - important | 43 | // 16bit keycodes - important |
| 49 | uint16_t keycode = keymap_key_to_keycode(layer, key); | 44 | uint16_t keycode = keymap_key_to_keycode(layer, key); |
| 50 | 45 | ||
| 51 | if (keycode >= 0x0100 && keycode < 0x2000) { | 46 | // keycode remapping |
| 52 | // Has a modifier | 47 | keycode = keycode_config(keycode); |
| 53 | action_t action; | ||
| 54 | // Split it up | ||
| 55 | action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key | ||
| 56 | return action; | ||
| 57 | } else if (keycode >= 0x2000 && keycode < 0x3000) { | ||
| 58 | // Is a shortcut for function layer, pull last 12bits | ||
| 59 | // This means we have 4,096 FN macros at our disposal | ||
| 60 | return keymap_func_to_action(keycode & 0xFFF); | ||
| 61 | } else if (keycode >= 0x3000 && keycode < 0x4000) { | ||
| 62 | // When the code starts with 3, it's an action macro. | ||
| 63 | action_t action; | ||
| 64 | action.code = ACTION_MACRO(keycode & 0xFF); | ||
| 65 | return action; | ||
| 66 | #ifdef BACKLIGHT_ENABLE | ||
| 67 | } else if (keycode >= BL_0 && keycode <= BL_15) { | ||
| 68 | action_t action; | ||
| 69 | action.code = ACTION_BACKLIGHT_LEVEL(keycode & 0x000F); | ||
| 70 | return action; | ||
| 71 | } else if (keycode == BL_DEC) { | ||
| 72 | action_t action; | ||
| 73 | action.code = ACTION_BACKLIGHT_DECREASE(); | ||
| 74 | return action; | ||
| 75 | } else if (keycode == BL_INC) { | ||
| 76 | action_t action; | ||
| 77 | action.code = ACTION_BACKLIGHT_INCREASE(); | ||
| 78 | return action; | ||
| 79 | } else if (keycode == BL_TOGG) { | ||
| 80 | action_t action; | ||
| 81 | action.code = ACTION_BACKLIGHT_TOGGLE(); | ||
| 82 | return action; | ||
| 83 | } else if (keycode == BL_STEP) { | ||
| 84 | action_t action; | ||
| 85 | action.code = ACTION_BACKLIGHT_STEP(); | ||
| 86 | return action; | ||
| 87 | #endif | ||
| 88 | } else if (keycode == RESET) { // RESET is 0x5000, which is why this is here | ||
| 89 | clear_keyboard(); | ||
| 90 | #ifdef AUDIO_ENABLE | ||
| 91 | play_notes(&goodbye, 5, false); | ||
| 92 | #endif | ||
| 93 | _delay_ms(250); | ||
| 94 | bootloader_jump(); | ||
| 95 | return; | ||
| 96 | } else if (keycode == DEBUG) { // DEBUG is 0x5001 | ||
| 97 | // TODO: Does this actually work? | ||
| 98 | print("\nDEBUG: enabled.\n"); | ||
| 99 | debug_enable = true; | ||
| 100 | return; | ||
| 101 | } else if (keycode >= 0x5000 && keycode < 0x6000) { | ||
| 102 | // Layer movement shortcuts | ||
| 103 | // See .h to see constraints/usage | ||
| 104 | int type = (keycode >> 0x8) & 0xF; | ||
| 105 | if (type == 0x1) { | ||
| 106 | // Layer set "GOTO" | ||
| 107 | int when = (keycode >> 0x4) & 0x3; | ||
| 108 | int layer = keycode & 0xF; | ||
| 109 | action_t action; | ||
| 110 | action.code = ACTION_LAYER_SET(layer, when); | ||
| 111 | return action; | ||
| 112 | } else if (type == 0x2) { | ||
| 113 | // Momentary layer | ||
| 114 | int layer = keycode & 0xFF; | ||
| 115 | action_t action; | ||
| 116 | action.code = ACTION_LAYER_MOMENTARY(layer); | ||
| 117 | return action; | ||
| 118 | } else if (type == 0x3) { | ||
| 119 | // Set default layer | ||
| 120 | int layer = keycode & 0xFF; | ||
| 121 | action_t action; | ||
| 122 | action.code = ACTION_DEFAULT_LAYER_SET(layer); | ||
| 123 | return action; | ||
| 124 | } else if (type == 0x4) { | ||
| 125 | // Set default layer | ||
| 126 | int layer = keycode & 0xFF; | ||
| 127 | action_t action; | ||
| 128 | action.code = ACTION_LAYER_TOGGLE(layer); | ||
| 129 | return action; | ||
| 130 | } | ||
| 131 | #ifdef MIDI_ENABLE | ||
| 132 | } else if (keycode >= 0x6000 && keycode < 0x7000) { | ||
| 133 | action_t action; | ||
| 134 | action.code = ACTION_FUNCTION_OPT(keycode & 0xFF, (keycode & 0x0F00) >> 8); | ||
| 135 | return action; | ||
| 136 | #endif | ||
| 137 | } else if (keycode >= 0x7000 && keycode < 0x8000) { | ||
| 138 | action_t action; | ||
| 139 | action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); | ||
| 140 | return action; | ||
| 141 | } else if (keycode >= 0x8000 && keycode < 0x9000) { | ||
| 142 | action_t action; | ||
| 143 | action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); | ||
| 144 | return action; | ||
| 145 | #ifdef UNICODE_ENABLE | ||
| 146 | } else if (keycode >= 0x8000000) { | ||
| 147 | action_t action; | ||
| 148 | uint16_t unicode = keycode & ~(0x8000); | ||
| 149 | action.code = ACTION_FUNCTION_OPT(unicode & 0xFF, (unicode & 0xFF00) >> 8); | ||
| 150 | return action; | ||
| 151 | #endif | ||
| 152 | } else { | ||
| 153 | 48 | ||
| 154 | } | 49 | action_t action; |
| 50 | uint8_t action_layer, when, mod; | ||
| 51 | // The arm-none-eabi compiler generates out of bounds warnings when using the fn_actions directly for some reason | ||
| 52 | const uint16_t* actions = fn_actions; | ||
| 155 | 53 | ||
| 156 | switch (keycode) { | 54 | switch (keycode) { |
| 157 | case KC_FN0 ... KC_FN31: | 55 | case KC_FN0 ... KC_FN31: |
| 158 | return keymap_fn_to_action(keycode); | 56 | action.code = pgm_read_word(&actions[FN_INDEX(keycode)]); |
| 159 | #ifdef BOOTMAGIC_ENABLE | 57 | break; |
| 160 | case KC_CAPSLOCK: | ||
| 161 | case KC_LOCKING_CAPS: | ||
| 162 | if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) { | ||
| 163 | return keycode_to_action(KC_LCTL); | ||
| 164 | } | ||
| 165 | return keycode_to_action(keycode); | ||
| 166 | case KC_LCTL: | ||
| 167 | if (keymap_config.swap_control_capslock) { | ||
| 168 | return keycode_to_action(KC_CAPSLOCK); | ||
| 169 | } | ||
| 170 | return keycode_to_action(KC_LCTL); | ||
| 171 | case KC_LALT: | ||
| 172 | if (keymap_config.swap_lalt_lgui) { | ||
| 173 | if (keymap_config.no_gui) { | ||
| 174 | return keycode_to_action(ACTION_NO); | ||
| 175 | } | ||
| 176 | return keycode_to_action(KC_LGUI); | ||
| 177 | } | ||
| 178 | return keycode_to_action(KC_LALT); | ||
| 179 | case KC_LGUI: | ||
| 180 | if (keymap_config.swap_lalt_lgui) { | ||
| 181 | return keycode_to_action(KC_LALT); | ||
| 182 | } | ||
| 183 | if (keymap_config.no_gui) { | ||
| 184 | return keycode_to_action(ACTION_NO); | ||
| 185 | } | ||
| 186 | return keycode_to_action(KC_LGUI); | ||
| 187 | case KC_RALT: | ||
| 188 | if (keymap_config.swap_ralt_rgui) { | ||
| 189 | if (keymap_config.no_gui) { | ||
| 190 | return keycode_to_action(ACTION_NO); | ||
| 191 | } | ||
| 192 | return keycode_to_action(KC_RGUI); | ||
| 193 | } | ||
| 194 | return keycode_to_action(KC_RALT); | ||
| 195 | case KC_RGUI: | ||
| 196 | if (keymap_config.swap_ralt_rgui) { | ||
| 197 | return keycode_to_action(KC_RALT); | ||
| 198 | } | ||
| 199 | if (keymap_config.no_gui) { | ||
| 200 | return keycode_to_action(ACTION_NO); | ||
| 201 | } | ||
| 202 | return keycode_to_action(KC_RGUI); | ||
| 203 | case KC_GRAVE: | ||
| 204 | if (keymap_config.swap_grave_esc) { | ||
| 205 | return keycode_to_action(KC_ESC); | ||
| 206 | } | ||
| 207 | return keycode_to_action(KC_GRAVE); | ||
| 208 | case KC_ESC: | ||
| 209 | if (keymap_config.swap_grave_esc) { | ||
| 210 | return keycode_to_action(KC_GRAVE); | ||
| 211 | } | ||
| 212 | return keycode_to_action(KC_ESC); | ||
| 213 | case KC_BSLASH: | ||
| 214 | if (keymap_config.swap_backslash_backspace) { | ||
| 215 | return keycode_to_action(KC_BSPACE); | ||
| 216 | } | ||
| 217 | return keycode_to_action(KC_BSLASH); | ||
| 218 | case KC_BSPACE: | ||
| 219 | if (keymap_config.swap_backslash_backspace) { | ||
| 220 | return keycode_to_action(KC_BSLASH); | ||
| 221 | } | ||
| 222 | return keycode_to_action(KC_BSPACE); | ||
| 223 | #endif | ||
| 224 | default: | ||
| 225 | return keycode_to_action(keycode); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | /* Macro */ | ||
| 231 | __attribute__ ((weak)) | ||
| 232 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 233 | { | ||
| 234 | return MACRO_NONE; | ||
| 235 | } | ||
| 236 | |||
| 237 | /* Function */ | ||
| 238 | __attribute__ ((weak)) | ||
| 239 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 240 | { | ||
| 241 | } | ||
| 242 | |||
| 243 | /* translates keycode to action */ | ||
| 244 | static action_t keycode_to_action(uint16_t keycode) | ||
| 245 | { | ||
| 246 | action_t action; | ||
| 247 | switch (keycode) { | ||
| 248 | case KC_A ... KC_EXSEL: | 58 | case KC_A ... KC_EXSEL: |
| 249 | case KC_LCTRL ... KC_RGUI: | 59 | case KC_LCTRL ... KC_RGUI: |
| 250 | action.code = ACTION_KEY(keycode); | 60 | action.code = ACTION_KEY(keycode); |
| @@ -252,7 +62,7 @@ static action_t keycode_to_action(uint16_t keycode) | |||
| 252 | case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE: | 62 | case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE: |
| 253 | action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode)); | 63 | action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode)); |
| 254 | break; | 64 | break; |
| 255 | case KC_AUDIO_MUTE ... KC_WWW_FAVORITES: | 65 | case KC_AUDIO_MUTE ... KC_MEDIA_REWIND: |
| 256 | action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode)); | 66 | action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode)); |
| 257 | break; | 67 | break; |
| 258 | case KC_MS_UP ... KC_MS_ACCEL2: | 68 | case KC_MS_UP ... KC_MS_ACCEL2: |
| @@ -261,6 +71,73 @@ static action_t keycode_to_action(uint16_t keycode) | |||
| 261 | case KC_TRNS: | 71 | case KC_TRNS: |
| 262 | action.code = ACTION_TRANSPARENT; | 72 | action.code = ACTION_TRANSPARENT; |
| 263 | break; | 73 | break; |
| 74 | case QK_MODS ... QK_MODS_MAX: ; | ||
| 75 | // Has a modifier | ||
| 76 | // Split it up | ||
| 77 | action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key | ||
| 78 | break; | ||
| 79 | case QK_FUNCTION ... QK_FUNCTION_MAX: ; | ||
| 80 | // Is a shortcut for function action_layer, pull last 12bits | ||
| 81 | // This means we have 4,096 FN macros at our disposal | ||
| 82 | action.code = pgm_read_word(&actions[(int)keycode & 0xFFF]); | ||
| 83 | break; | ||
| 84 | case QK_MACRO ... QK_MACRO_MAX: | ||
| 85 | action.code = ACTION_MACRO(keycode & 0xFF); | ||
| 86 | break; | ||
| 87 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: | ||
| 88 | action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); | ||
| 89 | break; | ||
| 90 | case QK_TO ... QK_TO_MAX: ; | ||
| 91 | // Layer set "GOTO" | ||
| 92 | when = (keycode >> 0x4) & 0x3; | ||
| 93 | action_layer = keycode & 0xF; | ||
| 94 | action.code = ACTION_LAYER_SET(action_layer, when); | ||
| 95 | break; | ||
| 96 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: ; | ||
| 97 | // Momentary action_layer | ||
| 98 | action_layer = keycode & 0xFF; | ||
| 99 | action.code = ACTION_LAYER_MOMENTARY(action_layer); | ||
| 100 | break; | ||
| 101 | case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: ; | ||
| 102 | // Set default action_layer | ||
| 103 | action_layer = keycode & 0xFF; | ||
| 104 | action.code = ACTION_DEFAULT_LAYER_SET(action_layer); | ||
| 105 | break; | ||
| 106 | case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: ; | ||
| 107 | // Set toggle | ||
| 108 | action_layer = keycode & 0xFF; | ||
| 109 | action.code = ACTION_LAYER_TOGGLE(action_layer); | ||
| 110 | break; | ||
| 111 | case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: ; | ||
| 112 | // OSL(action_layer) - One-shot action_layer | ||
| 113 | action_layer = keycode & 0xFF; | ||
| 114 | action.code = ACTION_LAYER_ONESHOT(action_layer); | ||
| 115 | break; | ||
| 116 | case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: ; | ||
| 117 | // OSM(mod) - One-shot mod | ||
| 118 | mod = keycode & 0xFF; | ||
| 119 | action.code = ACTION_MODS_ONESHOT(mod); | ||
| 120 | break; | ||
| 121 | case QK_MOD_TAP ... QK_MOD_TAP_MAX: | ||
| 122 | action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); | ||
| 123 | break; | ||
| 124 | #ifdef BACKLIGHT_ENABLE | ||
| 125 | case BL_0 ... BL_15: | ||
| 126 | action.code = ACTION_BACKLIGHT_LEVEL(keycode - BL_0); | ||
| 127 | break; | ||
| 128 | case BL_DEC: | ||
| 129 | action.code = ACTION_BACKLIGHT_DECREASE(); | ||
| 130 | break; | ||
| 131 | case BL_INC: | ||
| 132 | action.code = ACTION_BACKLIGHT_INCREASE(); | ||
| 133 | break; | ||
| 134 | case BL_TOGG: | ||
| 135 | action.code = ACTION_BACKLIGHT_TOGGLE(); | ||
| 136 | break; | ||
| 137 | case BL_STEP: | ||
| 138 | action.code = ACTION_BACKLIGHT_STEP(); | ||
| 139 | break; | ||
| 140 | #endif | ||
| 264 | default: | 141 | default: |
| 265 | action.code = ACTION_NO; | 142 | action.code = ACTION_NO; |
| 266 | break; | 143 | break; |
| @@ -268,22 +145,27 @@ static action_t keycode_to_action(uint16_t keycode) | |||
| 268 | return action; | 145 | return action; |
| 269 | } | 146 | } |
| 270 | 147 | ||
| 148 | __attribute__ ((weak)) | ||
| 149 | const uint16_t PROGMEM fn_actions[] = { | ||
| 271 | 150 | ||
| 272 | /* translates key to keycode */ | 151 | }; |
| 273 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) | 152 | |
| 153 | /* Macro */ | ||
| 154 | __attribute__ ((weak)) | ||
| 155 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 274 | { | 156 | { |
| 275 | // Read entire word (16bits) | 157 | return MACRO_NONE; |
| 276 | return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]); | ||
| 277 | } | 158 | } |
| 278 | 159 | ||
| 279 | /* translates Fn keycode to action */ | 160 | /* Function */ |
| 280 | action_t keymap_fn_to_action(uint16_t keycode) | 161 | __attribute__ ((weak)) |
| 162 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 281 | { | 163 | { |
| 282 | return (action_t){ .code = pgm_read_word(&fn_actions[FN_INDEX(keycode)]) }; | ||
| 283 | } | 164 | } |
| 284 | 165 | ||
| 285 | action_t keymap_func_to_action(uint16_t keycode) | 166 | /* translates key to keycode */ |
| 167 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) | ||
| 286 | { | 168 | { |
| 287 | // For FUNC without 8bit limit | 169 | // Read entire word (16bits) |
| 288 | return (action_t){ .code = pgm_read_word(&fn_actions[(int)keycode]) }; | 170 | return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]); |
| 289 | } | 171 | } |
diff --git a/quantum/keymap_common.h b/quantum/keymap_common.h deleted file mode 100644 index 3db40772e..000000000 --- a/quantum/keymap_common.h +++ /dev/null | |||
| @@ -1,214 +0,0 @@ | |||
| 1 | /* | ||
| 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 | #include <avr/pgmspace.h> | ||
| 25 | #include "keycode.h" | ||
| 26 | #include "keymap.h" | ||
| 27 | #include "action_macro.h" | ||
| 28 | #include "report.h" | ||
| 29 | #include "host.h" | ||
| 30 | // #include "print.h" | ||
| 31 | #include "debug.h" | ||
| 32 | |||
| 33 | #ifdef BOOTMAGIC_ENABLE | ||
| 34 | /* NOTE: Not portable. Bit field order depends on implementation */ | ||
| 35 | typedef union { | ||
| 36 | uint16_t raw; | ||
| 37 | struct { | ||
| 38 | bool swap_control_capslock:1; | ||
| 39 | bool capslock_to_control:1; | ||
| 40 | bool swap_lalt_lgui:1; | ||
| 41 | bool swap_ralt_rgui:1; | ||
| 42 | bool no_gui:1; | ||
| 43 | bool swap_grave_esc:1; | ||
| 44 | bool swap_backslash_backspace:1; | ||
| 45 | bool nkro:1; | ||
| 46 | }; | ||
| 47 | } keymap_config_t; | ||
| 48 | keymap_config_t keymap_config; | ||
| 49 | #endif | ||
| 50 | |||
| 51 | |||
| 52 | /* translates key to keycode */ | ||
| 53 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); | ||
| 54 | |||
| 55 | /* translates Fn keycode to action */ | ||
| 56 | action_t keymap_fn_to_action(uint16_t keycode); | ||
| 57 | |||
| 58 | /* translates Fn keycode to action */ | ||
| 59 | action_t keymap_func_to_action(uint16_t keycode); | ||
| 60 | |||
| 61 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | ||
| 62 | extern const uint16_t fn_actions[]; | ||
| 63 | |||
| 64 | // Ability to use mods in layouts | ||
| 65 | #define LCTL(kc) kc | 0x0100 | ||
| 66 | #define LSFT(kc) kc | 0x0200 | ||
| 67 | #define LALT(kc) kc | 0x0400 | ||
| 68 | #define LGUI(kc) kc | 0x0800 | ||
| 69 | #define HYPR(kc) kc | 0x0F00 | ||
| 70 | #define MEH(kc) kc | 0x0700 | ||
| 71 | #define LCAG(kc) kc | 0x0D00 // Modifier Ctrl Alt and GUI | ||
| 72 | |||
| 73 | #define RCTL(kc) kc | 0x1100 | ||
| 74 | #define RSFT(kc) kc | 0x1200 | ||
| 75 | #define RALT(kc) kc | 0x1400 | ||
| 76 | #define RGUI(kc) kc | 0x1800 | ||
| 77 | |||
| 78 | // Aliases for shifted symbols | ||
| 79 | // Each key has a 4-letter code, and some have longer aliases too. | ||
| 80 | // While the long aliases are descriptive, the 4-letter codes | ||
| 81 | // make for nicer grid layouts (everything lines up), and are | ||
| 82 | // the preferred style for Quantum. | ||
| 83 | #define KC_TILD LSFT(KC_GRV) // ~ | ||
| 84 | #define KC_TILDE KC_TILD | ||
| 85 | |||
| 86 | #define KC_EXLM LSFT(KC_1) // ! | ||
| 87 | #define KC_EXCLAIM KC_EXLM | ||
| 88 | |||
| 89 | #define KC_AT LSFT(KC_2) // @ | ||
| 90 | #define KC_HASH LSFT(KC_3) // # | ||
| 91 | |||
| 92 | #define KC_DLR LSFT(KC_4) // $ | ||
| 93 | #define KC_DOLLAR KC_DLR | ||
| 94 | |||
| 95 | #define KC_PERC LSFT(KC_5) // % | ||
| 96 | #define KC_PERCENT KC_PERC | ||
| 97 | |||
| 98 | #define KC_CIRC LSFT(KC_6) // ^ | ||
| 99 | #define KC_CIRCUMFLEX KC_CIRC | ||
| 100 | |||
| 101 | #define KC_AMPR LSFT(KC_7) // & | ||
| 102 | #define KC_AMPERSAND KC_AMPR | ||
| 103 | |||
| 104 | #define KC_ASTR LSFT(KC_8) // * | ||
| 105 | #define KC_ASTERISK KC_ASTR | ||
| 106 | |||
| 107 | #define KC_LPRN LSFT(KC_9) // ( | ||
| 108 | #define KC_LEFT_PAREN KC_LPRN | ||
| 109 | |||
| 110 | #define KC_RPRN LSFT(KC_0) // ) | ||
| 111 | #define KC_RIGHT_PAREN KC_RPRN | ||
| 112 | |||
| 113 | #define KC_UNDS LSFT(KC_MINS) // _ | ||
| 114 | #define KC_UNDERSCORE KC_UNDS | ||
| 115 | |||
| 116 | #define KC_PLUS LSFT(KC_EQL) // + | ||
| 117 | |||
| 118 | #define KC_LCBR LSFT(KC_LBRC) // { | ||
| 119 | #define KC_LEFT_CURLY_BRACE KC_LCBR | ||
| 120 | |||
| 121 | #define KC_RCBR LSFT(KC_RBRC) // } | ||
| 122 | #define KC_RIGHT_CURLY_BRACE KC_RCBR | ||
| 123 | |||
| 124 | #define KC_COLN LSFT(KC_SCLN) // : | ||
| 125 | #define KC_COLON KC_COLN | ||
| 126 | |||
| 127 | #define KC_PIPE LSFT(KC_BSLS) // | | ||
| 128 | |||
| 129 | #define KC_DELT KC_DELETE // Del key (four letter code) | ||
| 130 | |||
| 131 | // Alias for function layers than expand past FN31 | ||
| 132 | #define FUNC(kc) kc | 0x2000 | ||
| 133 | |||
| 134 | // Aliases | ||
| 135 | #define S(kc) LSFT(kc) | ||
| 136 | #define F(kc) FUNC(kc) | ||
| 137 | |||
| 138 | #define M(kc) kc | 0x3000 | ||
| 139 | |||
| 140 | #define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE) | ||
| 141 | |||
| 142 | // These affect the backlight (if your keyboard has one). | ||
| 143 | // We don't need to comment them out if your keyboard doesn't have a backlight, | ||
| 144 | // since they don't take up any space. | ||
| 145 | #define BL_ON 0x4009 | ||
| 146 | #define BL_OFF 0x4000 | ||
| 147 | #define BL_0 0x4000 | ||
| 148 | #define BL_1 0x4001 | ||
| 149 | #define BL_2 0x4002 | ||
| 150 | #define BL_3 0x4003 | ||
| 151 | #define BL_4 0x4004 | ||
| 152 | #define BL_5 0x4005 | ||
| 153 | #define BL_6 0x4006 | ||
| 154 | #define BL_7 0x4007 | ||
| 155 | #define BL_8 0x4008 | ||
| 156 | #define BL_9 0x4009 | ||
| 157 | #define BL_10 0x400A | ||
| 158 | #define BL_11 0x400B | ||
| 159 | #define BL_12 0x400C | ||
| 160 | #define BL_13 0x400D | ||
| 161 | #define BL_14 0x400E | ||
| 162 | #define BL_15 0x400F | ||
| 163 | #define BL_DEC 0x4010 | ||
| 164 | #define BL_INC 0x4011 | ||
| 165 | #define BL_TOGG 0x4012 | ||
| 166 | #define BL_STEP 0x4013 | ||
| 167 | |||
| 168 | #define RESET 0x5000 | ||
| 169 | #define DEBUG 0x5001 | ||
| 170 | |||
| 171 | // GOTO layer - 16 layers max | ||
| 172 | // when: | ||
| 173 | // ON_PRESS = 1 | ||
| 174 | // ON_RELEASE = 2 | ||
| 175 | // Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default. | ||
| 176 | #define TO(layer, when) (layer | 0x5100 | (when << 0x4)) | ||
| 177 | |||
| 178 | // Momentary switch layer - 256 layer max | ||
| 179 | #define MO(layer) (layer | 0x5200) | ||
| 180 | |||
| 181 | // Set default layer - 256 layer max | ||
| 182 | #define DF(layer) (layer | 0x5300) | ||
| 183 | |||
| 184 | // Toggle to layer - 256 layer max | ||
| 185 | #define TG(layer) (layer | 0x5400) | ||
| 186 | |||
| 187 | #define MIDI(n) (n | 0x6000) | ||
| 188 | |||
| 189 | // M-od, T-ap - 256 keycode max | ||
| 190 | #define MT(mod, kc) (kc | 0x7000 | ((mod & 0xF) << 8)) | ||
| 191 | #define CTL_T(kc) MT(0x1, kc) | ||
| 192 | #define SFT_T(kc) MT(0x2, kc) | ||
| 193 | #define ALT_T(kc) MT(0x4, kc) | ||
| 194 | #define GUI_T(kc) MT(0x8, kc) | ||
| 195 | #define C_S_T(kc) MT(0x3, kc) // Control + Shift e.g. for gnome-terminal | ||
| 196 | #define MEH_T(kc) MT(0x7, kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl | ||
| 197 | #define LCAG_T(kc) MT(0xD, kc) // Left control alt and gui | ||
| 198 | #define ALL_T(kc) MT(0xF, kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/ | ||
| 199 | |||
| 200 | // Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap | ||
| 201 | #define KC_HYPR HYPR(KC_NO) | ||
| 202 | #define KC_MEH MEH(KC_NO) | ||
| 203 | |||
| 204 | // L-ayer, T-ap - 256 keycode max, 16 layer max | ||
| 205 | #define LT(layer, kc) (kc | 0x8000 | ((layer & 0xF) << 8)) | ||
| 206 | |||
| 207 | // For sending unicode codes. | ||
| 208 | // You may not send codes over 1FFF -- this supports most of UTF8. | ||
| 209 | // To have a key that sends out Œ, go UC(0x0152) | ||
| 210 | #define UNICODE(n) (n | 0x8000) | ||
| 211 | #define UC(n) UNICODE(n) | ||
| 212 | |||
| 213 | |||
| 214 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h new file mode 100644 index 000000000..e5ef39552 --- /dev/null +++ b/quantum/keymap_extras/keymap_bepo.h | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | /* Keymap macros for the French BÉPO layout - http://bepo.fr */ | ||
| 2 | #ifndef KEYMAP_BEPO_H | ||
| 3 | #define KEYMAP_BEPO_H | ||
| 4 | |||
| 5 | #include "keymap.h" | ||
| 6 | |||
| 7 | // Alt gr | ||
| 8 | #ifndef ALTGR | ||
| 9 | #define ALTGR(kc) RALT(kc) | ||
| 10 | #endif | ||
| 11 | #ifndef ALGR | ||
| 12 | #define ALGR(kc) ALTGR(kc) | ||
| 13 | #endif | ||
| 14 | #define BP_ALGR KC_RALT | ||
| 15 | |||
| 16 | // Normal characters | ||
| 17 | // First row (on usual keyboards) | ||
| 18 | #define BP_DOLLAR KC_GRAVE // $ | ||
| 19 | #define BP_DLR BP_DOLLAR | ||
| 20 | #define BP_DOUBLE_QUOTE KC_1 // " | ||
| 21 | #define BP_DQOT BP_DOUBLE_QUOTE | ||
| 22 | #define BP_LEFT_GUILLEMET KC_2 // « | ||
| 23 | #define BP_LGIL BP_LEFT_GUILLEMET | ||
| 24 | #define BP_RIGHT_GUILLEMET KC_3 // » | ||
| 25 | #define BP_RGIL BP_RIGHT_GUILLEMET | ||
| 26 | #define BP_LEFT_PAREN KC_4 // ( | ||
| 27 | #define BP_LPRN BP_LEFT_PAREN | ||
| 28 | #define BP_RIGHT_PAREN KC_5 // ) | ||
| 29 | #define BP_RPRN BP_RIGHT_PAREN | ||
| 30 | #define BP_AT KC_6 // @ | ||
| 31 | #define BP_PLUS KC_7 // + | ||
| 32 | #define BP_MINUS KC_8 // - | ||
| 33 | #define BP_MINS BP_MINUS | ||
| 34 | #define BP_SLASH KC_9 // / | ||
| 35 | #define BP_SLSH BP_SLASH | ||
| 36 | #define BP_ASTERISK KC_0 // * | ||
| 37 | #define BP_ASTR BP_ASTERISK | ||
| 38 | #define BP_EQUAL KC_MINUS // = | ||
| 39 | #define BP_EQL BP_EQUAL | ||
| 40 | #define BP_PERCENT KC_EQUAL // % | ||
| 41 | #define BP_PERC BP_PERCENT | ||
| 42 | |||
| 43 | // Second row | ||
| 44 | #define BP_B KC_Q | ||
| 45 | #define BP_E_ACUTE KC_W // é | ||
| 46 | #define BP_ECUT BP_E_ACUTE | ||
| 47 | #define BP_P KC_E | ||
| 48 | #define BP_O KC_R | ||
| 49 | #define BP_E_GRAVE KC_T // è | ||
| 50 | #define BP_EGRV BP_E_GRAVE | ||
| 51 | #define BP_DEAD_CIRCUMFLEX KC_Y // dead ^ | ||
| 52 | #define BP_DCRC BP_DEAD_CIRCUMFLEX | ||
| 53 | #define BP_V KC_U | ||
| 54 | #define BP_D KC_I | ||
| 55 | #define BP_L KC_O | ||
| 56 | #define BP_J KC_P | ||
| 57 | #define BP_Z KC_LBRACKET | ||
| 58 | #define BP_W KC_RBRACKET | ||
| 59 | |||
| 60 | // Third row | ||
| 61 | #define BP_A KC_A | ||
| 62 | #define BP_U KC_S | ||
| 63 | #define BP_I KC_D | ||
| 64 | #define BP_E KC_F | ||
| 65 | #define BP_COMMA KC_G // , | ||
| 66 | #define BP_COMM BP_COMMA | ||
| 67 | #define BP_C KC_H | ||
| 68 | #define BP_T KC_J | ||
| 69 | #define BP_S KC_K | ||
| 70 | #define BP_R KC_L | ||
| 71 | #define BP_N KC_SCOLON | ||
| 72 | #define BP_M KC_QUOTE | ||
| 73 | #define BP_C_CEDILLA KC_BSLASH // ç | ||
| 74 | #define BP_CCED BP_C_CEDILLA | ||
| 75 | |||
| 76 | // Fourth row | ||
| 77 | #define BP_E_CIRCUMFLEX KC_NONUS_BSLASH // ê | ||
| 78 | #define BP_ECRC BP_E_CIRCUMFLEX | ||
| 79 | #define BP_A_GRAVE KC_Z // à | ||
| 80 | #define BP_AGRV BP_A_GRAVE | ||
| 81 | #define BP_Y KC_X | ||
| 82 | #define BP_X KC_C | ||
| 83 | #define BP_DOT KC_V // . | ||
| 84 | #define BP_K KC_B | ||
| 85 | #define BP_APOSTROPHE KC_N | ||
| 86 | #define BP_APOS BP_APOSTROPHE // ' | ||
| 87 | #define BP_Q KC_M | ||
| 88 | #define BP_G KC_COMMA | ||
| 89 | #define BP_H KC_DOT | ||
| 90 | #define BP_F KC_SLASH | ||
| 91 | |||
| 92 | // Shifted characters | ||
| 93 | // First row | ||
| 94 | #define BP_HASH LSFT(BP_DOLLAR) // # | ||
| 95 | #define BP_1 LSFT(KC_1) | ||
| 96 | #define BP_2 LSFT(KC_2) | ||
| 97 | #define BP_3 LSFT(KC_3) | ||
| 98 | #define BP_4 LSFT(KC_4) | ||
| 99 | #define BP_5 LSFT(KC_5) | ||
| 100 | #define BP_6 LSFT(KC_6) | ||
| 101 | #define BP_7 LSFT(KC_7) | ||
| 102 | #define BP_8 LSFT(KC_8) | ||
| 103 | #define BP_9 LSFT(KC_9) | ||
| 104 | #define BP_0 LSFT(KC_0) | ||
| 105 | #define BP_DEGREE LSFT(BP_EQUAL) // ° | ||
| 106 | #define BP_DEGR BP_DEGREE | ||
| 107 | #define BP_GRAVE LSFT(BP_PERCENT) // ` | ||
| 108 | #define BP_GRV BP_GRAVE | ||
| 109 | |||
| 110 | // Second row | ||
| 111 | #define BP_EXCLAIM LSFT(BP_DEAD_CIRCUMFLEX) // ! | ||
| 112 | #define BP_EXLM BP_EXCLAIM | ||
| 113 | |||
| 114 | // Third row | ||
| 115 | #define BP_SCOLON LSFT(BP_COMMA) // ; | ||
| 116 | #define BP_SCLN BP_SCOLON | ||
| 117 | |||
| 118 | // Fourth row | ||
| 119 | #define BP_COLON LSFT(BP_DOT) // : | ||
| 120 | #define BP_COLN BP_COLON | ||
| 121 | #define BP_QUESTION LSFT(BP_APOS) // ? | ||
| 122 | #define BP_QEST BP_QUESTION | ||
| 123 | |||
| 124 | // Space bar | ||
| 125 | #define BP_NON_BREAKING_SPACE LSFT(KC_SPACE) | ||
| 126 | #define BP_NBSP BP_NON_BREAKING_SPACE | ||
| 127 | |||
| 128 | // AltGr-ed characters | ||
| 129 | // First row | ||
| 130 | #define BP_EN_DASH ALTGR(BP_DOLLAR) // – | ||
| 131 | #define BP_NDSH BP_EN_DASH | ||
| 132 | #define BP_EM_DASH ALTGR(KC_1) // — | ||
| 133 | #define BP_MDSH BP_EM_DASH | ||
| 134 | #define BP_LESS ALTGR(KC_2) // < | ||
| 135 | #define BP_GREATER ALTGR(KC_3) // > | ||
| 136 | #define BP_GRTR BP_GREATER | ||
| 137 | #define BP_LBRACKET ALTGR(KC_4) // [ | ||
| 138 | #define BP_LBRC BP_LBRACKET | ||
| 139 | #define BP_RBRACKET ALTGR(KC_5) // ] | ||
| 140 | #define BP_RBRC BP_RBRACKET | ||
| 141 | #define BP_CIRCUMFLEX ALTGR(KC_6) // ^ | ||
| 142 | #define BP_CIRC BP_CIRCUMFLEX | ||
| 143 | #define BP_PLUS_MINUS ALTGR(KC_7) // ± | ||
| 144 | #define BP_PSMS BP_PLUS_MINUS | ||
| 145 | #define BP_MATH_MINUS ALTGR(KC_8) // − | ||
| 146 | #define BP_MMNS BP_MATH_MINUS | ||
| 147 | #define BP_OBELUS ALTGR(KC_9) // ÷ | ||
| 148 | #define BP_OBEL BP_OBELUS | ||
| 149 | // more conventional name of the symbol | ||
| 150 | #define BP_DIVISION_SIGN BP_OBELUS | ||
| 151 | #define BP_DVSN BP_DIVISION_SIGN | ||
| 152 | #define BP_TIMES ALTGR(KC_0) // × | ||
| 153 | #define BP_TIMS BP_TIMES | ||
| 154 | #define BP_DIFFERENT ALTGR(BP_EQUAL) // ≠ | ||
| 155 | #define BP_DIFF BP_DIFFERENT | ||
| 156 | #define BP_PERMILLE ALTGR(BP_PERCENT) // ‰ | ||
| 157 | #define BP_PMIL BP_PERMILLE | ||
| 158 | |||
| 159 | // Second row | ||
| 160 | #define BP_PIPE ALTGR(BP_B) // | | ||
| 161 | #define BP_DEAD_ACUTE ALTGR(BP_E_ACUTE) // dead ´ | ||
| 162 | #define BP_DACT BP_DEAD_ACUTE | ||
| 163 | #define BP_AMPERSAND ALTGR(BP_P) // & | ||
| 164 | #define BP_AMPR BP_AMPERSAND | ||
| 165 | #define BP_OE_LIGATURE ALTGR(BP_O) // œ | ||
| 166 | #define BP_OE BP_OE_LIGATURE | ||
| 167 | #define BP_DEAD_GRAVE ALTGR(BP_E_GRAVE) // ` | ||
| 168 | #define BP_DGRV BP_DEAD_GRAVE | ||
| 169 | #define BP_INVERTED_EXCLAIM ALTGR(BP_DEAD_CIRCUMFLEX) // ¡ | ||
| 170 | #define BP_IXLM BP_INVERTED_EXCLAIM | ||
| 171 | #define BP_DEAD_CARON ALTGR(BP_V) // dead ˇ | ||
| 172 | #define BP_DCAR BP_DEAD_CARON | ||
| 173 | #define BP_ETH ALTGR(BP_D) // ð | ||
| 174 | #define BP_DEAD_SLASH ALTGR(BP_L) // dead / | ||
| 175 | #define BP_DSLH BP_DEAD_SLASH | ||
| 176 | #define BP_IJ_LIGATURE ALTGR(BP_J) // ij | ||
| 177 | #define BP_IJ BP_IJ_LIGATURE | ||
| 178 | #define BP_SCHWA ALTGR(BP_Z) // ə | ||
| 179 | #define BP_SCWA BP_SCHWA | ||
| 180 | #define BP_DEAD_BREVE ALTGR(BP_W) // dead ˘ | ||
| 181 | #define BP_DBRV BP_DEAD_BREVE | ||
| 182 | |||
| 183 | // Third row | ||
| 184 | #define BP_AE_LIGATURE ALTGR(BP_A) // æ | ||
| 185 | #define BP_AE BP_AE_LIGATURE | ||
| 186 | #define BP_U_GRAVE ALTGR(BP_U) // ù | ||
| 187 | #define BP_UGRV BP_U_GRAVE | ||
| 188 | #define BP_DEAD_TREMA ALTGR(BP_I) // dead ¨ (trema/umlaut/diaresis) | ||
| 189 | #define BP_DTRM BP_DEAD_TREMA | ||
| 190 | #define BP_EURO ALTGR(BP_E) // € | ||
| 191 | #define BP_TYPOGRAPHICAL_APOSTROPHE ALTGR(BP_COMMMA) // ’ | ||
| 192 | #define BP_TAPO BP_TYPOGRAPHICAL_APOSTROPHE | ||
| 193 | #define BP_COPYRIGHT ALTGR(BP_C) // © | ||
| 194 | #define BP_CPRT BP_COPYRIGHT | ||
| 195 | #define BP_THORN ALTGR(BP_T) // þ | ||
| 196 | #define BP_THRN BP_THORN | ||
| 197 | #define BP_SHARP_S ALTGR(BP_S) // ß | ||
| 198 | #define BP_SRPS BP_SHARP_S | ||
| 199 | #define BP_REGISTERED_TRADEMARK ALTGR(BP_R) // ® | ||
| 200 | #define BP_RTM BP_REGISTERED_TRADEMARK | ||
| 201 | #define BP_DEAD_TILDE ALTGR(BP_N) // dead ~ | ||
| 202 | #define BP_DTLD BP_DEAD_TILDE | ||
| 203 | #define BP_DEAD_MACRON ALTGR(BP_M) // dead ¯ | ||
| 204 | #define BP_DMCR BP_DEAD_MACRON | ||
| 205 | #define BP_DEAD_CEDILLA ALTGR(BP_C_CEDILLA) // dead ¸ | ||
| 206 | #define BP_DCED BP_DEAD_CEDILLA | ||
| 207 | |||
| 208 | // Fourth row | ||
| 209 | #define BP_NONUS_SLASH ALTGR(BP_E_CIRCUMFLEX) // / on non-us backslash key (102nd key, ê in bépo) | ||
| 210 | #define BP_NUSL BP_NONUS_SLASH | ||
| 211 | #define BP_BACKSLASH ALTGR(BP_A_GRAVE) /* \ */ | ||
| 212 | #define BP_BSLS BP_BACKSLASH | ||
| 213 | #define BP_LEFT_CURLY_BRACE ALTGR(BP_Y) // { | ||
| 214 | #define BP_LCBR BP_LEFT_CURLY_BRACE | ||
| 215 | #define BP_RIGHT_CURLY_BRACE ALTGR(BP_X) // } | ||
| 216 | #define BP_RCBR BP_RIGHT_CURLY_BRACE | ||
| 217 | #define BP_ELLIPSIS ALTGR(BP_DOT) // … | ||
| 218 | #define BP_ELPS BP_ELLIPSIS | ||
| 219 | #define BP_TILDE ALTGR(BP_K) // ~ | ||
| 220 | #define BP_TILD BP_TILDE | ||
| 221 | #define BP_INVERTED_QUESTION ALTGR(BP_QUESTION) // ¿ | ||
| 222 | #define BP_IQST BP_INVERTED_QUESTION | ||
| 223 | #define BP_DEAD_RING ALTGR(BP_Q) // dead ° | ||
| 224 | #define BP_DRNG BP_DEAD_RING | ||
| 225 | #define BP_DEAD_GREEK ALTGR(BP_G) // dead Greek key (following key will make a Greek letter) | ||
| 226 | #define BP_DGRK BP_DEAD_GREEK | ||
| 227 | #define BP_DAGGER ALTGR(BP_H) // † | ||
| 228 | #define BP_DAGR BP_DAGGER | ||
| 229 | #define BP_DEAD_OGONEK ALTGR(BP_F) // dead ˛ | ||
| 230 | #define BP_DOGO BP_DEAD_OGONEK | ||
| 231 | |||
| 232 | // Space bar | ||
| 233 | #define BP_UNDERSCORE ALTGR(KC_SPACE) // _ | ||
| 234 | #define BP_UNDS BP_UNDERSCORE | ||
| 235 | |||
| 236 | // AltGr-Shifted characters (different from capitalised AltGr-ed characters) | ||
| 237 | // First row | ||
| 238 | #define BP_PARAGRAPH ALTGR(BP_HASH) // ¶ | ||
| 239 | #define BP_PARG BP_PARAGRAPH | ||
| 240 | #define BP_LOW_DOUBLE_QUOTE ALTGR(BP_1) // „ | ||
| 241 | #define BP_LWQT BP_LOW_DOUBLE_QUOTE | ||
| 242 | #define BP_LEFT_DOUBLE_QUOTE ALTGR(BP_2) // “ | ||
| 243 | #define BP_LDQT BP_LEFT_DOUBLE_QUOTE | ||
| 244 | #define BP_RIGHT_DOUBLE_QUOTE ALTGR(BP_3) // ” | ||
| 245 | #define BP_RDQT BP_RIGHT_DOUBLE_QUOTE | ||
| 246 | #define BP_LESS_OR_EQUAL ALTGR(BP_4) // ≤ | ||
| 247 | #define BP_LEQL BP_LESS_OR_EQUAL | ||
| 248 | #define BP_GREATER_OR_EQUAL ALTGR(BP_5) // ≥ | ||
| 249 | #define BP_GEQL BP_GREATER_OR_EQUAL | ||
| 250 | // nothing on ALTGR(BP_6) | ||
| 251 | #define BP_NEGATION ALTGR(BP_7) // ¬ | ||
| 252 | #define BP_NEGT BP_NEGATION | ||
| 253 | #define BP_ONE_QUARTER ALTGR(BP_8) // ¼ | ||
| 254 | #define BP_1QRT BP_ONE_QUARTER | ||
| 255 | #define BP_ONE_HALF ALTGR(BP_9) // ½ | ||
| 256 | #define BP_1HLF BP_ONE_HALF | ||
| 257 | #define BP_THREE_QUARTERS ALTGR(BP_0) // ¾ | ||
| 258 | #define BP_3QRT BP_THREE_QUARTERS | ||
| 259 | #define BP_MINUTES ALTGR(BP_DEGREE) // ′ | ||
| 260 | #define BP_MNUT BP_MINUTES | ||
| 261 | #define BP_SECONDS ALTGR(BP_GRAVE) // ″ | ||
| 262 | #define BP_SCND BP_SECONDS | ||
| 263 | |||
| 264 | // Second row | ||
| 265 | #define BP_BROKEN_PIPE LSFT(BP_PIPE) // ¦ | ||
| 266 | #define BP_BPIP BP_BROKEN_PIPE | ||
| 267 | #define BP_DEAD_DOUBLE_ACUTE LSFT(BP_DEAD_ACUTE) // ˝ | ||
| 268 | #define BP_DDCT BP_DEAD_DOUBLE_ACUTE | ||
| 269 | #define BP_SECTION ALTGR(LSFT(BP_P)) // § | ||
| 270 | #define BP_SECT BP_SECTION | ||
| 271 | // LSFT(BP_DEAD_GRAVE) is actually the same character as LSFT(BP_PERCENT) | ||
| 272 | #define BP_GRAVE_BIS LSFT(BP_DEAD_GRAVE) // ` | ||
| 273 | #define BP_GRVB BP_GRAVE_BIS | ||
| 274 | |||
| 275 | // Third row | ||
| 276 | #define BP_DEAD_DOT_ABOVE LSFT(BP_DEAD_TREMA) // dead ˙ | ||
| 277 | #define BP_DDTA BP_DEAD_DOT_ABOVE | ||
| 278 | #define BP_DEAD_CURRENCY LSFT(BP_EURO) // dead ¤ (next key will generate a currency code like ¥ or £) | ||
| 279 | #define BP_DCUR BP_DEAD_CURRENCY | ||
| 280 | #define BP_DEAD_HORN LSFT(ALTGR(BP_COMMA)) // dead ̛ | ||
| 281 | #define BP_DHRN BP_DEAD_HORN | ||
| 282 | #define BP_LONG_S LSFT(ALTGR(BP_C)) // ſ | ||
| 283 | #define BP_LNGS BP_LONG_S | ||
| 284 | #define BP_TRADEMARK LSFT(BP_REGISTERED_TRADEMARK) // ™ | ||
| 285 | #define BP_TM BP_TRADEMARK | ||
| 286 | #define BP_ORDINAL_INDICATOR_O LSFT(ALTGR(BP_M)) // º | ||
| 287 | #define BP_ORDO BP_ORDINAL_INDICATOR_O | ||
| 288 | #define BP_DEAD_COMMA LSFT(BP_DEAD_CEDILLA) // dead ˛ | ||
| 289 | #define BP_DCOM BP_DEAD_COMMA | ||
| 290 | |||
| 291 | // Fourth row | ||
| 292 | #define BP_LEFT_QUOTE LSFT(ALTGR(BP_Y)) // ‘ | ||
| 293 | #define BP_LQOT BP_LEFT_QUOTE | ||
| 294 | #define BP_RIGHT_QUOTE LSFT(ALTGR(BP_X)) // ’ | ||
| 295 | #define BP_RQOT BP_RIGHT_QUOTE | ||
| 296 | #define BP_INTERPUNCT LSFT(ALTGR(BP_DOT)) // · | ||
| 297 | #define BP_IPCT BP_INTERPUNCT | ||
| 298 | #define BP_DEAD_HOOK_ABOVE LSFT(ALTGR(BP_QUESTION)) // dead ̉ | ||
| 299 | #define BP_DHKA BP_DEAD_HOOK_ABOVE | ||
| 300 | #define BP_DEAD_UNDERDOT LSFT(BP_DEAD_RING) // dead ̣ | ||
| 301 | #define BP_DUDT BP_DEAD_UNDERDOT | ||
| 302 | #define BP_DOUBLE_DAGGER LSFT(BP_DAGGER) // ‡ | ||
| 303 | #define BP_DDGR BP_DOUBLE_DAGGER | ||
| 304 | #define BP_ORDINAL_INDICATOR_A LSFT(ALTGR(BP_F)) // ª | ||
| 305 | #define BP_ORDA BP_ORDINAL_INDICATOR_A | ||
| 306 | |||
| 307 | // Space bar | ||
| 308 | #define BP_NARROW_NON_BREAKING_SPACE ALTGR(BP_NON_BREAKING_SPACE) | ||
| 309 | #define BP_NNBS BP_NARROW_NON_BREAKING_SPACE | ||
| 310 | |||
| 311 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_canadian_multilingual.h b/quantum/keymap_extras/keymap_canadian_multilingual.h new file mode 100644 index 000000000..0bc20c7b9 --- /dev/null +++ b/quantum/keymap_extras/keymap_canadian_multilingual.h | |||
| @@ -0,0 +1,255 @@ | |||
| 1 | #ifndef KEYMAP_CANADIAN_MULTILINGUAG_H | ||
| 2 | #define KEYMAP_CANADIAN_MULTILINGUAG_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #ifndef ALTGR | ||
| 8 | #define ALTGR(kc) RALT(kc) | ||
| 9 | #endif | ||
| 10 | #ifndef ALGR | ||
| 11 | #define ALGR(kc) ALTGR(kc) | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #define CSA_ALTGR KC_RALT | ||
| 15 | #define CSA_ALGR CSA_ALTGR | ||
| 16 | |||
| 17 | #ifndef GR2A | ||
| 18 | #define GR2A(kc) RCTL(kc) | ||
| 19 | #endif | ||
| 20 | |||
| 21 | // Normal characters | ||
| 22 | // First row | ||
| 23 | #define CSA_SLASH KC_GRV // / | ||
| 24 | #define CSA_SLSH CSA_SLASH | ||
| 25 | |||
| 26 | // Second row | ||
| 27 | #define CSA_DEAD_CIRCUMFLEX KC_LBRACKET // dead ^ | ||
| 28 | #define CSA_DCRC CSA_DEAD_CIRCUMFLEX | ||
| 29 | #define CSA_C_CEDILLA KC_RBRACKET // Ç | ||
| 30 | #define CSA_CCED CSA_C_CEDILLA | ||
| 31 | |||
| 32 | // Third row | ||
| 33 | #define CSA_E_GRAVE KC_QUOT // è | ||
| 34 | #define CSA_EGRV CSA_E_GRAVE | ||
| 35 | #define CSA_A_GRAVE KC_BSLASH // à | ||
| 36 | #define CSA_AGRV CSA_A_GRAVE | ||
| 37 | |||
| 38 | // Fourth row | ||
| 39 | #define CSA_U_GRAVE KC_NONUS_BSLASH // ù | ||
| 40 | #define CSA_UGRV CSA_U_GRAVE | ||
| 41 | #define CSA_E_ACUTE KC_SLSH // é | ||
| 42 | #define CSA_ECUT CSA_E_ACUTE | ||
| 43 | |||
| 44 | // Shifted characters | ||
| 45 | // First row | ||
| 46 | #define CSA_BACKSLASH LSFT(CSA_SLASH) /* \ */ | ||
| 47 | #define CSA_BSLS CSA_BACKSLASH | ||
| 48 | #define CSA_QUESTION LSFT(KC_6) // ? | ||
| 49 | #define CSA_QEST CSA_QUESTION | ||
| 50 | |||
| 51 | // Second row | ||
| 52 | #define CSA_DEAD_TREMA LSFT(CSA_DEAD_CIRCUMFLEX) // dead trema/umlaut/diaresis for ä ë ï ö ü | ||
| 53 | #define CSA_DTRM CSA_DEAD_TREMA | ||
| 54 | |||
| 55 | // Third row | ||
| 56 | // all same as US-QWERTY, or capitalised character of the non-shifted key | ||
| 57 | |||
| 58 | // Fourth row | ||
| 59 | #define CSA_APOSTROPHE LSFT(KC_COMMA) // ' | ||
| 60 | #define CSA_APOS CSA_APOSTROPHE | ||
| 61 | #define CSA_DOUBLE_QUOTE LSFT(KC_DOT) // " | ||
| 62 | #define CSA_DQOT CSA_DOUBLE_QUOTE | ||
| 63 | |||
| 64 | // Alt Gr-ed characters | ||
| 65 | // First row | ||
| 66 | #define CSA_PIPE ALTGR(CSA_SLASH) // | | ||
| 67 | #define CSA_CURRENCY ALTGR(KC_4) // ¤ | ||
| 68 | #define CSA_CURR CSA_CURRENCY | ||
| 69 | #define CSA_LEFT_CURLY_BRACE ALTGR(KC_7) // { | ||
| 70 | #define CSA_LCBR CSA_LEFT_CURLY_BRACE | ||
| 71 | #define CSA_RIGHT_CURLY_BRACE ALTGR(KC_8) // } | ||
| 72 | #define CSA_RCBR CSA_RIGHT_CURLY_BRACE | ||
| 73 | #define CSA_LBRACKET ALTGR(KC_9) // [ | ||
| 74 | #define CSA_LBRC CSA_LBRACKET | ||
| 75 | #define CSA_RBRACKET ALTGR(KC_0) // ] | ||
| 76 | #define CSA_RBRC CSA_RBRACKET | ||
| 77 | #define CSA_NEGATION ALTGR(KC_EQUAL) // ¬ | ||
| 78 | #define CSA_NEGT CSA_NEGATION | ||
| 79 | |||
| 80 | // Second row | ||
| 81 | // euro symbol not available on Linux? (X.org) | ||
| 82 | #define CSA_EURO ALTGR(KC_E) // € | ||
| 83 | #define CSA_DEAD_GRAVE ALTGR(CSA_DEAD_CIRCUMFLEX) | ||
| 84 | #define CSA_DGRV CSA_DEAD_GRAVE // dead ` | ||
| 85 | #define CSA_DEAD_TILDE ALTGR(CSA_C_CEDILLA) // ~ | ||
| 86 | #define CSA_DTLD CSA_DEAD_TILDE | ||
| 87 | |||
| 88 | // Third row | ||
| 89 | #define CSA_DEGREE ALTGR(KC_SCOLON) // ° | ||
| 90 | #define CSA_DEGR CSA_DEGREE | ||
| 91 | |||
| 92 | // Fourth row | ||
| 93 | #define CSA_LEFT_GUILLEMET ALTGR(KC_Z) // « | ||
| 94 | #define CSA_LGIL CSA_LEFT_GUILLEMET | ||
| 95 | #define CSA_RIGHT_GUILLEMET ALTGR(KC_X) // » | ||
| 96 | #define CSA_RGIL CSA_RIGHT_GUILLEMET | ||
| 97 | #define CSA_LESS ALTGR(KC_COMMA) // < | ||
| 98 | #define CSA_GREATER ALTGR(KC_DOT) // > | ||
| 99 | #define CSA_GRTR CSA_GREATER | ||
| 100 | |||
| 101 | // Space bar | ||
| 102 | #define CSA_NON_BREAKING_SPACE ALTGR(KC_SPACE) | ||
| 103 | #define CSA_NBSP CSA_NON_BREAKING_SPACE | ||
| 104 | |||
| 105 | // GR2A-ed characters | ||
| 106 | // First row | ||
| 107 | #define CSA_SUPERSCRIPT_ONE GR2A(KC_1) // ¹ | ||
| 108 | #define CSA_SUP1 CSA_SUPERSCRIPT_ONE | ||
| 109 | #define CSA_SUPERSCRIPT_TWO GR2A(KC_2) // ² | ||
| 110 | #define CSA_SUP2 CSA_SUPERSCRIPT_TWO | ||
| 111 | #define CSA_SUPERSCRIPT_THREE GR2A(KC_3) // ³ | ||
| 112 | #define CSA_SUP3 CSA_SUPERSCRIPT_THREE | ||
| 113 | #define CSA_ONE_QUARTER GR2A(KC_4) // ¼ | ||
| 114 | #define CSA_1QRT CSA_ONE_QUARTER | ||
| 115 | #define CSA_ONE_HALF GR2A(KC_5) // ½ | ||
| 116 | #define CSA_1HLF CSA_ONE_HALF | ||
| 117 | #define CSA_THREE_QUARTERS GR2A(KC_6) // ¾ | ||
| 118 | #define CSA_3QRT CSA_THREE_QUARTERS | ||
| 119 | // nothing on 7-0 and - | ||
| 120 | #define CSA_DEAD_CEDILLA GR2A(KC_EQUAL) // dead ¸ | ||
| 121 | #define CSA_DCED CSA_DEAD_CEDILLA | ||
| 122 | |||
| 123 | // Second row | ||
| 124 | #define CSA_OMEGA GR2A(KC_Q) // ω | ||
| 125 | #define CSA_OMEG CSA_OMEGA | ||
| 126 | #define CSA_L_STROKE GR2A(KC_W) // ł | ||
| 127 | #define CSA_LSTK CSA_L_STROKE | ||
| 128 | #define CSA_OE_LIGATURE GR2A(KC_E) // œ | ||
| 129 | #define CSA_OE CSA_OE_LIGATURE | ||
| 130 | #define CSA_PARAGRAPH GR2A(KC_R) // ¶ | ||
| 131 | #define CSA_PARG CSA_PARAGRAPH | ||
| 132 | #define CSA_T_STROKE GR2A(KC_T) // ŧ | ||
| 133 | #define CSA_LEFT_ARROW GR2A(KC_Y) // ← | ||
| 134 | #define CSA_LARW CSA_LEFT_ARROW | ||
| 135 | #define CSA_DOWN_ARROW GR2A(KC_U) // ↓ | ||
| 136 | #define CSA_DARW CSA_DOWN_ARROW | ||
| 137 | #define CSA_RIGHT_ARROW GR2A(KC_I) // → | ||
| 138 | #define CSA_RARW CSA_RIGHT_ARROW | ||
| 139 | #define CSA_O_STROKE GR2A(KC_O) // ø | ||
| 140 | #define CSA_OSTK CSA_O_STROKE | ||
| 141 | #define CSA_THORN GR2A(KC_P) // þ | ||
| 142 | #define CSA_THRN CSA_THORN | ||
| 143 | // nothing on ^ | ||
| 144 | #define CSA_TILDE GR2A(CSA_C_CEDILLA) // dead ~ | ||
| 145 | #define CSA_TILD CSA_TILDE | ||
| 146 | |||
| 147 | // Third row | ||
| 148 | #define CSA_AE_LIGATURE GR2A(KC_A) // æ | ||
| 149 | #define CSA_AE CSA_AE_LIGATURE | ||
| 150 | #define CSA_SHARP_S GR2A(KC_S) // ß | ||
| 151 | #define CSA_SRPS CSA_SHARP_S | ||
| 152 | #define CSA_ETH GR2A(KC_D) // ð | ||
| 153 | // nothing on F | ||
| 154 | #define CSA_ENG GR2A(KC_G) // ŋ | ||
| 155 | #define CSA_H_SRTOKE GR2A(KC_H) // ħ | ||
| 156 | #define CSA_HSTK CSA_H_SRTOKE | ||
| 157 | #define CSA_IJ_LIGATURE GR2A(KC_J) // ij | ||
| 158 | #define CSA_IJ CSA_IJ_LIGATURE | ||
| 159 | #define CSA_KRA GR2A(KC_K) // ĸ | ||
| 160 | #define CSA_L_FLOWN_DOT GR2A(KC_L) // ŀ | ||
| 161 | #define CSA_LFLD CSA_L_FLOWN_DOT | ||
| 162 | #define CSA_DEAD_ACUTE GR2A(KC_SCLN) // dead acute accent | ||
| 163 | #define CSA_DACT CSA_DEAD_ACUTE | ||
| 164 | // nothing on È & À | ||
| 165 | |||
| 166 | // Fourth row | ||
| 167 | #define CSA_CENT GR2A(KC_C) // ¢ | ||
| 168 | #define CSA_LEFT_DOUBLE_QUOTE GR2A(KC_V) // “ | ||
| 169 | #define CSA_LDQT CSA_LEFT_DOUBLE_QUOTE | ||
| 170 | #define CSA_RIGHT_DOUBLE_QUOTE GR2A(KC_B) // ” | ||
| 171 | #define CSA_RDQT CSA_RIGHT_DOUBLE_QUOTE | ||
| 172 | #define CSA_N_APOSTROPHE GR2A(KC_N) // ʼn (deprecated unicode codepoint) | ||
| 173 | #define CSA_NAPO CSA_N_APOSTROPHE | ||
| 174 | #define CSA_MU GR2A(KC_M) // μ | ||
| 175 | #define CSA_HORIZONTAL_BAR GR2A(KC_COMMA) // ― | ||
| 176 | #define CSA_HZBR CSA_HORIZONTAL_BAR | ||
| 177 | #define CSA_DEAD_DOT_ABOVE GR2A(KC_DOT) // dead ˙ | ||
| 178 | #define CSA_DDTA CSA_DEAD_DOT_ABOVE | ||
| 179 | |||
| 180 | // GR2A-shifted characters (different from capitalised GR2A-ed characters) | ||
| 181 | // First row | ||
| 182 | #define CSA_SOFT_HYPHEN GR2A(LSFT(CSA_SLASH)) // soft-hyphen, appears as a hyphen in wrapped word | ||
| 183 | #define CSA_SHYP CSA_SOFT_HYPHEN | ||
| 184 | #define CSA_INVERTED_EXCLAIM GR2A(KC_EXCLAIM) // ¡ | ||
| 185 | #define CSA_IXLM CSA_INVERTED_EXCLAIM | ||
| 186 | // nothing on 2 | ||
| 187 | #define CSA_POUND GR2A(LSFT(KC_3)) // £ | ||
| 188 | #define CSA_GBP CSA_POUND_SIGN | ||
| 189 | // already on ALTGR(KC_E) | ||
| 190 | #define CSA_EURO_BIS GR2A(LSFT(KC_4)) // € | ||
| 191 | #define CSA_EURB CSA_EURO_BIS | ||
| 192 | #define CSA_THREE_EIGHTHS GR2A(LSFT(KC_5)) // ⅜ | ||
| 193 | #define CSA_3ON8 CSA_THREE_EIGHTHS | ||
| 194 | #define CSA_FIVE_EIGHTHS GR2A(LSFT(KC_6)) // ⅝ | ||
| 195 | #define CSA_5ON8 CSA_FIVE_EIGHTHS | ||
| 196 | #define CSA_SEVEN_EIGHTHS GR2A(LSFT(KC_7)) // ⅞ | ||
| 197 | #define CSA_7ON8 CSA_SEVEN_EIGHTHS | ||
| 198 | #define CSA_TRADEMARK GR2A(LSFT(KC_8)) // ™ | ||
| 199 | #define CSA_TM CSA_TRADEMARK | ||
| 200 | #define CSA_PLUS_MINUS GR2A(LSFT(KC_9)) // ± | ||
| 201 | #define CSA_PSMS CSA_PLUS_MINUS | ||
| 202 | // nothing on 0 | ||
| 203 | #define CSA_INVERTED_QUESTION GR2A(LSFT(KC_MINUS)) // ¿ | ||
| 204 | #define CSA_IQST CSA_INVERTED_QUESTION | ||
| 205 | #define CSA_DEAD_OGONEK GR2A(LSFT(KC_EQUAL)) // dead ˛ | ||
| 206 | #define CSA_DOGO CSA_DEAD_OGONEK | ||
| 207 | |||
| 208 | // Second row | ||
| 209 | #define CSA_REGISTERED_TRADEMARK GR2A(LSFT(KC_R)) // ® | ||
| 210 | #define CSA_RTM CSA_REGISTERED_TRADEMARK | ||
| 211 | #define CSA_YEN GR2A(LSFT(KC_Y)) // ¥ | ||
| 212 | #define CSA_YUAN CSA_YEN | ||
| 213 | #define CSA_UP_ARROW LSFT(CSA_DOWN_ARROW) // ↑ | ||
| 214 | #define CSA_DOTLESS_I GR2A(LSFT(KC_I)) // ı | ||
| 215 | #define CSA_DLSI CSA_DOTLESS_I | ||
| 216 | #define CSA_DEAD_RING GR2A(LSFT(CSA_DCRC)) // dead ° | ||
| 217 | #define CSA_DRNG CSA_DEAD_RING | ||
| 218 | #define CSA_DEAD_MACRON GR2A(LSFT(CSA_C_CEDILLA)) // dead ¯ | ||
| 219 | #define CSA_DMCR CSA_DEAD_MACRON | ||
| 220 | |||
| 221 | // Third row | ||
| 222 | #define CSA_SECTION GR2A(LSFT(KC_S)) // § | ||
| 223 | #define CSA_SECT CSA_SECTION | ||
| 224 | #define CSA_ORDINAL_INDICATOR_A GR2A(LSFT(KC_F)) // ª | ||
| 225 | #define CSA_ORDA CSA_ORDINAL_INDICATOR_A | ||
| 226 | #define CSA_DEAD_DOUBLE_ACUTE LSFT(CSA_DEAD_ACUTE) // ˝ | ||
| 227 | #define CSA_DDCT CSA_DEAD_DOUBLE_ACUTE | ||
| 228 | #define CSA_DEAD_CARON GR2A(LSFT(CSA_E_GRAVE)) // dead ˇ | ||
| 229 | #define CSA_DCAR CSA_DEAD_CARON | ||
| 230 | #define CSA_DEAD_BREVE GR2A(LSFT(CSA_A_GRAVE)) // dead ˘ | ||
| 231 | #define CSA_DBRV CSA_DEAD_BREVE | ||
| 232 | |||
| 233 | // Fourth row | ||
| 234 | #define CSA_BROKEN_PIPE GR2A(LSFT(CSA_U_GRAVE)) // ¦ | ||
| 235 | #define CSA_BPIP CSA_BROKEN_PIPE | ||
| 236 | #define CSA_COPYRIGHT GR2A(LSFT(KC_C)) // © | ||
| 237 | #define CSA_CPRT CSA_COPYRIGHT | ||
| 238 | #define CSA_LEFT_QUOTE GR2A(LSFT(KC_V)) // ‘ | ||
| 239 | #define CSA_LQOT CSA_LEFT_QUOTE | ||
| 240 | #define CSA_RIGHT_QUOTE GR2A(LSFT(KC_B)) // ’ | ||
| 241 | #define CSA_RQOT CSA_RIGHT_QUOTE | ||
| 242 | #define CSA_EIGHTH_NOTE GR2A(LSFT(KC_N)) // ♪ | ||
| 243 | #define CSA_8NOT CSA_EIGHTH_NOTE | ||
| 244 | #define CSA_ORDINAL_INDICATOR_O GR2A(LSFT(KC_M)) // º | ||
| 245 | #define CSA_ORDO CSA_ORDINAL_INDICATOR_O | ||
| 246 | #define CSA_TIMES GR2A(LSFT(KC_COMMA)) // × | ||
| 247 | #define CSA_TIMS CSA_TIMES | ||
| 248 | #define CSA_OBELUS GR2A(LSFT(KC_DOT)) // ÷ | ||
| 249 | #define CSA_OBEL CSA_OBELUS | ||
| 250 | // more conventional name of the symbol | ||
| 251 | #define CSA_DIVISION_SIGN CSA_OBELUS | ||
| 252 | #define CSA_DVSN CSA_DIVISION_SIGN | ||
| 253 | // TODO GR2A(LSFT(CSA_E_ACUTE)) | ||
| 254 | |||
| 255 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_colemak.h b/quantum/keymap_extras/keymap_colemak.h index 8a418c615..b8d615748 100644 --- a/quantum/keymap_extras/keymap_colemak.h +++ b/quantum/keymap_extras/keymap_colemak.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef KEYMAP_COLEMAK_H | 1 | #ifndef KEYMAP_COLEMAK_H |
| 2 | #define KEYMAP_COLEMAK_H | 2 | #define KEYMAP_COLEMAK_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | // For software implementation of colemak | 5 | // For software implementation of colemak |
| 6 | #define CM_Q KC_Q | 6 | #define CM_Q KC_Q |
| 7 | #define CM_W KC_W | 7 | #define CM_W KC_W |
diff --git a/quantum/keymap_extras/keymap_dvorak.h b/quantum/keymap_extras/keymap_dvorak.h index d172e0019..a0feed850 100644 --- a/quantum/keymap_extras/keymap_dvorak.h +++ b/quantum/keymap_extras/keymap_dvorak.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef KEYMAP_DVORAK_H | 1 | #ifndef KEYMAP_DVORAK_H |
| 2 | #define KEYMAP_DVORAK_H | 2 | #define KEYMAP_DVORAK_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Normal characters | 6 | // Normal characters |
| 7 | #define DV_GRV KC_GRV | 7 | #define DV_GRV KC_GRV |
| @@ -18,18 +18,19 @@ | |||
| 18 | #define DV_LBRC KC_MINS | 18 | #define DV_LBRC KC_MINS |
| 19 | #define DV_RBRC KC_EQL | 19 | #define DV_RBRC KC_EQL |
| 20 | 20 | ||
| 21 | #define DV_QUOT KC_Q | 21 | #define DV_QUOT KC_Q |
| 22 | #define DV_COMM KC_W | 22 | #define DV_COMM KC_W |
| 23 | #define DV_DOT KC_E | 23 | #define DV_DOT KC_E |
| 24 | #define DV_P KC_R | 24 | #define DV_P KC_R |
| 25 | #define DV_Y KC_T | 25 | #define DV_Y KC_T |
| 26 | #define DV_F KC_Y | 26 | #define DV_F KC_Y |
| 27 | #define DV_G KC_U | 27 | #define DV_G KC_U |
| 28 | #define DV_C KC_I | 28 | #define DV_C KC_I |
| 29 | #define DV_R KC_O | 29 | #define DV_R KC_O |
| 30 | #define DV_L KC_P | 30 | #define DV_L KC_P |
| 31 | #define DV_SLSH KC_LBRC | 31 | #define DV_SLSH KC_LBRC |
| 32 | #define DV_EQL KC_RBRC | 32 | #define DV_EQL KC_RBRC |
| 33 | #define DV_BSLS KC_BSLS | ||
| 33 | 34 | ||
| 34 | #define DV_A KC_A | 35 | #define DV_A KC_A |
| 35 | #define DV_O KC_S | 36 | #define DV_O KC_S |
| @@ -69,4 +70,16 @@ | |||
| 69 | #define DV_LCBR LSFT(DV_LBRC) | 70 | #define DV_LCBR LSFT(DV_LBRC) |
| 70 | #define DV_RCBR LSFT(DV_RBRC) | 71 | #define DV_RCBR LSFT(DV_RBRC) |
| 71 | 72 | ||
| 72 | #endif \ No newline at end of file | 73 | #define DV_DQUO LSFT(DV_QUOT) |
| 74 | #define DV_LABK LSFT(DV_COMM) | ||
| 75 | #define DV_RABK LSFT(DV_DOT) | ||
| 76 | |||
| 77 | #define DV_QUES LSFT(DV_SLSH) | ||
| 78 | #define DV_PLUS LSFT(DV_EQL) | ||
| 79 | #define DV_PIPE LSFT(DV_BSLS) | ||
| 80 | |||
| 81 | #define DV_UNDS LSFT(DV_MINS) | ||
| 82 | |||
| 83 | #define DV_COLN LSFT(DV_SCLN) | ||
| 84 | |||
| 85 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_dvp.h b/quantum/keymap_extras/keymap_dvp.h new file mode 100644 index 000000000..83f49a52b --- /dev/null +++ b/quantum/keymap_extras/keymap_dvp.h | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | #ifndef KEYMAP_DVP_H | ||
| 2 | #define KEYMAP_DVP_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Normal characters | ||
| 7 | #define DP_DLR KC_GRV | ||
| 8 | #define DP_AMPR KC_1 | ||
| 9 | #define DP_LBRC KC_2 | ||
| 10 | #define DP_LCBR KC_3 | ||
| 11 | #define DP_RCBR KC_4 | ||
| 12 | #define DP_LPRN KC_5 | ||
| 13 | #define DP_EQL KC_6 | ||
| 14 | #define DP_ASTR KC_7 | ||
| 15 | #define DP_RPRN KC_8 | ||
| 16 | #define DP_PLUS KC_9 | ||
| 17 | #define DP_RBRC KC_0 | ||
| 18 | #define DP_EXLM KC_MINS | ||
| 19 | #define DP_HASH KC_EQL | ||
| 20 | |||
| 21 | #define DP_SCLN KC_Q | ||
| 22 | #define DP_COMM KC_W | ||
| 23 | #define DP_DOT KC_E | ||
| 24 | #define DP_P KC_R | ||
| 25 | #define DP_Y KC_T | ||
| 26 | #define DP_F KC_Y | ||
| 27 | #define DP_G KC_U | ||
| 28 | #define DP_C KC_I | ||
| 29 | #define DP_R KC_O | ||
| 30 | #define DP_L KC_P | ||
| 31 | #define DP_SLSH KC_LBRC | ||
| 32 | #define DP_AT KC_RBRC | ||
| 33 | #define DP_BSLS KC_BSLS | ||
| 34 | |||
| 35 | #define DP_A KC_A | ||
| 36 | #define DP_O KC_S | ||
| 37 | #define DP_E KC_D | ||
| 38 | #define DP_U KC_F | ||
| 39 | #define DP_I KC_G | ||
| 40 | #define DP_D KC_H | ||
| 41 | #define DP_H KC_J | ||
| 42 | #define DP_T KC_K | ||
| 43 | #define DP_N KC_L | ||
| 44 | #define DP_S KC_SCLN | ||
| 45 | #define DP_MINS KC_QUOT | ||
| 46 | |||
| 47 | #define DP_QUOT KC_Z | ||
| 48 | #define DP_Q KC_X | ||
| 49 | #define DP_J KC_C | ||
| 50 | #define DP_K KC_V | ||
| 51 | #define DP_X KC_B | ||
| 52 | #define DP_B KC_N | ||
| 53 | #define DP_M KC_M | ||
| 54 | #define DP_W KC_COMM | ||
| 55 | #define DP_V KC_DOT | ||
| 56 | #define DP_Z KC_SLSH | ||
| 57 | |||
| 58 | // Shifted characters | ||
| 59 | #define DP_TILD LSFT(DP_DLR) | ||
| 60 | #define DP_PERC LSFT(DP_AMPR) | ||
| 61 | #define DP_7 LSFT(DP_LBRC) | ||
| 62 | #define DP_5 LSFT(DP_LCBR) | ||
| 63 | #define DP_3 LSFT(DP_RCBR) | ||
| 64 | #define DP_1 LSFT(DP_LPRN) | ||
| 65 | #define DP_9 LSFT(DP_EQL) | ||
| 66 | #define DP_0 LSFT(DP_ASTR) | ||
| 67 | #define DP_2 LSFT(DP_RPRN) | ||
| 68 | #define DP_4 LSFT(DP_PLUS) | ||
| 69 | #define DP_6 LSFT(DP_RBRC) | ||
| 70 | #define DP_8 LSFT(DP_EXLM) | ||
| 71 | #define DP_GRV LSFT(DP_HASH) | ||
| 72 | |||
| 73 | #define DP_COLN LSFT(DP_SCLN) | ||
| 74 | #define DP_LABK LSFT(DP_COMM) | ||
| 75 | #define DP_RABK LSFT(DP_DOT) | ||
| 76 | #define DP_QUES LSFT(DP_SLSH) | ||
| 77 | #define DP_CIRC LSFT(DP_AT) | ||
| 78 | #define DP_PIPE LSFT(DP_BSLS) | ||
| 79 | #define DP_UNDS LSFT(DP_MINS) | ||
| 80 | #define DP_DQUO LSFT(DP_QUOT) | ||
| 81 | |||
| 82 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_fr_ch.h b/quantum/keymap_extras/keymap_fr_ch.h new file mode 100644 index 000000000..87d4bb24c --- /dev/null +++ b/quantum/keymap_extras/keymap_fr_ch.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #ifndef KEYMAP_FR_CH | ||
| 2 | #define KEYMAP_FR_CH | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) RALT(kc) | ||
| 8 | #define FR_CH_ALGR KC_RALT | ||
| 9 | |||
| 10 | // normal characters | ||
| 11 | #define FR_CH_Z KC_Y | ||
| 12 | #define FR_CH_Y KC_Z | ||
| 13 | |||
| 14 | #define FR_CH_A KC_A | ||
| 15 | #define FR_CH_B KC_B | ||
| 16 | #define FR_CH_C KC_C | ||
| 17 | #define FR_CH_D KC_D | ||
| 18 | #define FR_CH_E KC_E | ||
| 19 | #define FR_CH_F KC_F | ||
| 20 | #define FR_CH_G KC_G | ||
| 21 | #define FR_CH_H KC_H | ||
| 22 | #define FR_CH_I KC_I | ||
| 23 | #define FR_CH_J KC_J | ||
| 24 | #define FR_CH_K KC_K | ||
| 25 | #define FR_CH_L KC_L | ||
| 26 | #define FR_CH_M KC_M | ||
| 27 | #define FR_CH_N KC_N | ||
| 28 | #define FR_CH_O KC_O | ||
| 29 | #define FR_CH_P KC_P | ||
| 30 | #define FR_CH_Q KC_Q | ||
| 31 | #define FR_CH_R KC_R | ||
| 32 | #define FR_CH_S KC_S | ||
| 33 | #define FR_CH_T KC_T | ||
| 34 | #define FR_CH_U KC_U | ||
| 35 | #define FR_CH_V KC_V | ||
| 36 | #define FR_CH_W KC_W | ||
| 37 | #define FR_CH_X KC_X | ||
| 38 | |||
| 39 | #define FR_CH_0 KC_0 | ||
| 40 | #define FR_CH_1 KC_1 | ||
| 41 | #define FR_CH_2 KC_2 | ||
| 42 | #define FR_CH_3 KC_3 | ||
| 43 | #define FR_CH_4 KC_4 | ||
| 44 | #define FR_CH_5 KC_5 | ||
| 45 | #define FR_CH_6 KC_6 | ||
| 46 | #define FR_CH_7 KC_7 | ||
| 47 | #define FR_CH_8 KC_8 | ||
| 48 | #define FR_CH_9 KC_9 | ||
| 49 | |||
| 50 | #define FR_CH_DOT KC_DOT | ||
| 51 | #define FR_CH_COMM KC_COMM | ||
| 52 | |||
| 53 | #define FR_CH_QUOT KC_MINS | ||
| 54 | #define FR_CH_AE KC_QUOT | ||
| 55 | #define FR_CH_UE KC_LBRC | ||
| 56 | #define FR_CH_OE KC_SCLN | ||
| 57 | |||
| 58 | #define FR_CH_CIRC KC_EQL // accent circumflex ^ and grave ` and ~ | ||
| 59 | #define FR_CH_LESS KC_NUBS // < and > and backslash | ||
| 60 | #define FR_CH_MINS KC_SLSH // - and _ | ||
| 61 | #define FR_CH_DLR KC_BSLS // $, £ and } | ||
| 62 | #define FR_CH_PARA KC_GRV // § and ring ° | ||
| 63 | #define FR_CH_DIAE KC_RBRC // accent ¨ | ||
| 64 | |||
| 65 | // shifted characters | ||
| 66 | #define FR_CH_RING LSFT(KC_GRV) // ° | ||
| 67 | #define FR_CH_EXLM LSFT(KC_RBRC) // ! | ||
| 68 | #define FR_CH_PLUS LSFT(KC_1) // + | ||
| 69 | #define FR_CH_DQOT LSFT(KC_2) // " | ||
| 70 | #define FR_CH_ASTR LSFT(KC_3) // * | ||
| 71 | #define FR_CH_PERC LSFT(KC_5) // % | ||
| 72 | #define FR_CH_AMPR LSFT(KC_6) // & | ||
| 73 | #define FR_CH_SLSH LSFT(KC_7) // / | ||
| 74 | #define FR_CH_LPRN LSFT(KC_8) // ( | ||
| 75 | #define FR_CH_RPRN LSFT(KC_9) // ) | ||
| 76 | #define FR_CH_EQL LSFT(KC_0) // = | ||
| 77 | #define FR_CH_QST LSFT(FR_CH_QUOT) // ? | ||
| 78 | #define FR_CH_MORE LSFT(FR_CH_LESS) // > | ||
| 79 | #define FR_CH_COLN LSFT(KC_DOT) // : | ||
| 80 | #define FR_CH_SCLN LSFT(KC_COMM) // ; | ||
| 81 | #define FR_CH_UNDS LSFT(FR_CH_MINS) // _ | ||
| 82 | #define FR_CH_CCED LSFT(KC_4) // ç | ||
| 83 | #define FR_CH_GRV LSFT(FR_CH_CIRC) // accent grave ` | ||
| 84 | |||
| 85 | // Alt Gr-ed characters | ||
| 86 | #define FR_CH_LCBR ALGR(KC_QUOT) // { | ||
| 87 | #define FR_CH_LBRC ALGR(KC_LBRC) // [ | ||
| 88 | #define FR_CH_RBRC ALGR(KC_9) // ] | ||
| 89 | #define FR_CH_RCBR ALGR(KC_0) // } | ||
| 90 | #define FR_CH_BSLS ALGR(FR_CH_LESS) // backslash | ||
| 91 | #define FR_CH_AT ALGR(KC_2) // @ | ||
| 92 | #define FR_CH_EURO ALGR(KC_E) // € | ||
| 93 | #define FR_CH_TILD ALGR(FR_CH_CIRC) // ~ | ||
| 94 | #define FR_CH_PIPE ALGR(KC_1) // | | ||
| 95 | #define FR_CH_HASH ALGR(KC_3) // # | ||
| 96 | #define FR_CH_ACUT ALGR(FR_CH_QUOT) // accent acute ´ | ||
| 97 | |||
| 98 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_french.h b/quantum/keymap_extras/keymap_french.h index ccfaed8f0..834c69650 100644 --- a/quantum/keymap_extras/keymap_french.h +++ b/quantum/keymap_extras/keymap_french.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | #ifndef KEYMAP_FRENCH_H | 1 | #ifndef KEYMAP_FRENCH_H |
| 2 | #define KEYMAP_FRENCH_H | 2 | #define KEYMAP_FRENCH_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Alt gr | 6 | // Alt gr |
| 7 | #define ALGR(kc) kc | 0x1400 | 7 | #define ALGR(kc) RALT(kc) |
| 8 | #define NO_ALGR KC_RALT | 8 | #define NO_ALGR KC_RALT |
| 9 | 9 | ||
| 10 | // Normal characters | 10 | // Normal characters |
| @@ -75,9 +75,9 @@ | |||
| 75 | #define FR_CIRC ALGR(KC_9) | 75 | #define FR_CIRC ALGR(KC_9) |
| 76 | #define FR_AT ALGR(KC_0) | 76 | #define FR_AT ALGR(KC_0) |
| 77 | #define FR_RBRC ALGR(FR_RPRN) | 77 | #define FR_RBRC ALGR(FR_RPRN) |
| 78 | #define FR_LCBR ALGR(FR_EQL) | 78 | #define FR_RCBR ALGR(FR_EQL) |
| 79 | 79 | ||
| 80 | #define FR_EURO ALGR(KC_E) | 80 | #define FR_EURO ALGR(KC_E) |
| 81 | #define FR_BULT ALGR(FR_DLR) | 81 | #define FR_BULT ALGR(FR_DLR) |
| 82 | 82 | ||
| 83 | #endif \ No newline at end of file | 83 | #endif |
diff --git a/quantum/keymap_extras/keymap_french_osx.h b/quantum/keymap_extras/keymap_french_osx.h index eb31bfb4d..004d73ee2 100644 --- a/quantum/keymap_extras/keymap_french_osx.h +++ b/quantum/keymap_extras/keymap_french_osx.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef KEYMAP_FRENCH_OSX_H | 1 | #ifndef KEYMAP_FRENCH_OSX_H |
| 2 | #define KEYMAP_FRENCH_OSX_H | 2 | #define KEYMAP_FRENCH_OSX_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Normal characters | 6 | // Normal characters |
| 7 | #define FR_AT KC_GRV | 7 | #define FR_AT KC_GRV |
diff --git a/quantum/keymap_extras/keymap_german.h b/quantum/keymap_extras/keymap_german.h index dbad26f8a..7e2e0ed44 100644 --- a/quantum/keymap_extras/keymap_german.h +++ b/quantum/keymap_extras/keymap_german.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | #ifndef KEYMAP_GERMAN | 1 | #ifndef KEYMAP_GERMAN |
| 2 | #define KEYMAP_GERMAN | 2 | #define KEYMAP_GERMAN |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Alt gr | 6 | // Alt gr |
| 7 | #define ALGR(kc) kc | 0x1400 | 7 | #define ALGR(kc) RALT(kc) |
| 8 | #define DE_ALGR KC_RALT | 8 | #define DE_ALGR KC_RALT |
| 9 | 9 | ||
| 10 | // normal characters | 10 | // normal characters |
diff --git a/quantum/keymap_extras/keymap_german_ch.h b/quantum/keymap_extras/keymap_german_ch.h new file mode 100644 index 000000000..b66d582a4 --- /dev/null +++ b/quantum/keymap_extras/keymap_german_ch.h | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #ifndef KEYMAP_SWISS_GERMAN | ||
| 2 | #define KEYMAP_SWISS_GERMAN | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) RALT(kc) | ||
| 8 | #define CH_ALGR KC_RALT | ||
| 9 | |||
| 10 | // normal characters | ||
| 11 | #define CH_Z KC_Y | ||
| 12 | #define CH_Y KC_Z | ||
| 13 | |||
| 14 | #define CH_A KC_A | ||
| 15 | #define CH_B KC_B | ||
| 16 | #define CH_C KC_C | ||
| 17 | #define CH_D KC_D | ||
| 18 | #define CH_E KC_E | ||
| 19 | #define CH_F KC_F | ||
| 20 | #define CH_G KC_G | ||
| 21 | #define CH_H KC_H | ||
| 22 | #define CH_I KC_I | ||
| 23 | #define CH_J KC_J | ||
| 24 | #define CH_K KC_K | ||
| 25 | #define CH_L KC_L | ||
| 26 | #define CH_M KC_M | ||
| 27 | #define CH_N KC_N | ||
| 28 | #define CH_O KC_O | ||
| 29 | #define CH_P KC_P | ||
| 30 | #define CH_Q KC_Q | ||
| 31 | #define CH_R KC_R | ||
| 32 | #define CH_S KC_S | ||
| 33 | #define CH_T KC_T | ||
| 34 | #define CH_U KC_U | ||
| 35 | #define CH_V KC_V | ||
| 36 | #define CH_W KC_W | ||
| 37 | #define CH_X KC_X | ||
| 38 | |||
| 39 | #define CH_0 KC_0 | ||
| 40 | #define CH_1 KC_1 | ||
| 41 | #define CH_2 KC_2 | ||
| 42 | #define CH_3 KC_3 | ||
| 43 | #define CH_4 KC_4 | ||
| 44 | #define CH_5 KC_5 | ||
| 45 | #define CH_6 KC_6 | ||
| 46 | #define CH_7 KC_7 | ||
| 47 | #define CH_8 KC_8 | ||
| 48 | #define CH_9 KC_9 | ||
| 49 | |||
| 50 | #define CH_DOT KC_DOT | ||
| 51 | #define CH_COMM KC_COMM | ||
| 52 | |||
| 53 | #define CH_QUOT KC_MINS // ' ? ´ | ||
| 54 | #define CH_AE KC_QUOT | ||
| 55 | #define CH_UE KC_LBRC | ||
| 56 | #define CH_OE KC_SCLN | ||
| 57 | |||
| 58 | #define CH_PARA KC_GRAVE // secction sign § and ° | ||
| 59 | #define CH_CARR KC_EQL // carret ^ ` ~ | ||
| 60 | #define CH_DIER KC_RBRC // dieresis ¨ ! ] | ||
| 61 | #define CH_DLR KC_BSLS // $ £ } | ||
| 62 | #define CH_LESS KC_NUBS // < and > and backslash | ||
| 63 | #define CH_MINS KC_SLSH // - and _ | ||
| 64 | |||
| 65 | // shifted characters | ||
| 66 | #define CH_RING LSFT(CH_PARA) // ° | ||
| 67 | #define CH_PLUS LSFT(KC_1) // + | ||
| 68 | #define CH_DQOT LSFT(KC_2) // " | ||
| 69 | #define CH_PAST LSFT(KC_3) // * | ||
| 70 | #define CH_CELA LSFT(KC_4) // ç | ||
| 71 | #define CH_PERC LSFT(KC_5) // % | ||
| 72 | #define CH_AMPR LSFT(KC_6) // & | ||
| 73 | #define CH_SLSH LSFT(KC_7) // / | ||
| 74 | #define CH_LPRN LSFT(KC_8) // ( | ||
| 75 | #define CH_RPRN LSFT(KC_9) // ) | ||
| 76 | #define CH_EQL LSFT(KC_0) // = | ||
| 77 | #define CH_QST LSFT(CH_QUOT) // ? | ||
| 78 | #define CH_GRV LSFT(CH_CARR) // ` | ||
| 79 | #define CH_EXLM LSFT(CH_DIER) // ! | ||
| 80 | #define CH_POND LSFT(CH_DLR) // £ | ||
| 81 | #define CH_MORE LSFT(CH_LESS) // > | ||
| 82 | #define CH_COLN LSFT(KC_DOT) // : | ||
| 83 | #define CH_SCLN LSFT(KC_COMM) // ; | ||
| 84 | #define CH_UNDS LSFT(CH_MINS) // _ | ||
| 85 | |||
| 86 | // Alt Gr-ed characters | ||
| 87 | #define CH_BRBR ALGR(KC_1) // ¦ brocken bar | ||
| 88 | #define CH_AT ALGR(KC_2) // @ | ||
| 89 | #define CH_HASH ALGR(KC_3) // # | ||
| 90 | #define CH_NOTL ALGR(KC_6) // ¬ negative logic | ||
| 91 | #define CH_PIPE ALGR(KC_7) // | | ||
| 92 | #define CH_CENT ALGR(KC_8) // ¢ cent | ||
| 93 | #define CH_ACUT ALGR(CH_QUOT) // ´ | ||
| 94 | #define CH_TILD ALGR(CH_CARR) // ~ | ||
| 95 | #define CH_EURO ALGR(KC_E) // € | ||
| 96 | #define CH_LBRC ALGR(CH_UE) // [ | ||
| 97 | #define CH_RBRC ALGR(CH_DIER) // ] | ||
| 98 | #define CH_LCBR ALGR(CH_AE) // { | ||
| 99 | #define CH_RCBR ALGR(CH_DLR) // } | ||
| 100 | #define CH_BSLS ALGR(CH_LESS) // backslash | ||
| 101 | |||
| 102 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_german_osx.h b/quantum/keymap_extras/keymap_german_osx.h index b011561e2..f63f06618 100644 --- a/quantum/keymap_extras/keymap_german_osx.h +++ b/quantum/keymap_extras/keymap_german_osx.h | |||
| @@ -1,100 +1,97 @@ | |||
| 1 | #ifndef KEYMAP_GERMAN_OSX | 1 | #ifndef KEYMAP_GERMAN_OSX |
| 2 | #define KEYMAP_GERMAN_OSX | 2 | #define KEYMAP_GERMAN_OSX |
| 3 | 3 | ||
| 4 | #ifdef KEYMAP_GERMAN | 4 | #include "keymap.h" |
| 5 | #warning redefining german keys | ||
| 6 | #endif | ||
| 7 | #include "keymap_common.h" | ||
| 8 | 5 | ||
| 9 | // Alt gr | 6 | // Alt gr |
| 10 | 7 | ||
| 11 | // normal characters | 8 | // normal characters |
| 12 | #define DE_Z KC_Y | 9 | #define DE_OSX_Z KC_Y |
| 13 | #define DE_Y KC_Z | 10 | #define DE_OSX_Y KC_Z |
| 14 | 11 | ||
| 15 | #define DE_A KC_A | 12 | #define DE_OSX_A KC_A |
| 16 | #define DE_B KC_B | 13 | #define DE_OSX_B KC_B |
| 17 | #define DE_C KC_C | 14 | #define DE_OSX_C KC_C |
| 18 | #define DE_D KC_D | 15 | #define DE_OSX_D KC_D |
| 19 | #define DE_E KC_E | 16 | #define DE_OSX_E KC_E |
| 20 | #define DE_F KC_F | 17 | #define DE_OSX_F KC_F |
| 21 | #define DE_G KC_G | 18 | #define DE_OSX_G KC_G |
| 22 | #define DE_H KC_H | 19 | #define DE_OSX_H KC_H |
| 23 | #define DE_I KC_I | 20 | #define DE_OSX_I KC_I |
| 24 | #define DE_J KC_J | 21 | #define DE_OSX_J KC_J |
| 25 | #define DE_K KC_K | 22 | #define DE_OSX_K KC_K |
| 26 | #define DE_L KC_L | 23 | #define DE_OSX_L KC_L |
| 27 | #define DE_M KC_M | 24 | #define DE_OSX_M KC_M |
| 28 | #define DE_N KC_N | 25 | #define DE_OSX_N KC_N |
| 29 | #define DE_O KC_O | 26 | #define DE_OSX_O KC_O |
| 30 | #define DE_P KC_P | 27 | #define DE_OSX_P KC_P |
| 31 | #define DE_Q KC_Q | 28 | #define DE_OSX_Q KC_Q |
| 32 | #define DE_R KC_R | 29 | #define DE_OSX_R KC_R |
| 33 | #define DE_S KC_S | 30 | #define DE_OSX_S KC_S |
| 34 | #define DE_T KC_T | 31 | #define DE_OSX_T KC_T |
| 35 | #define DE_U KC_U | 32 | #define DE_OSX_U KC_U |
| 36 | #define DE_V KC_V | 33 | #define DE_OSX_V KC_V |
| 37 | #define DE_W KC_W | 34 | #define DE_OSX_W KC_W |
| 38 | #define DE_X KC_X | 35 | #define DE_OSX_X KC_X |
| 39 | 36 | ||
| 40 | #define DE_0 KC_0 | 37 | #define DE_OSX_0 KC_0 |
| 41 | #define DE_1 KC_1 | 38 | #define DE_OSX_1 KC_1 |
| 42 | #define DE_2 KC_2 | 39 | #define DE_OSX_2 KC_2 |
| 43 | #define DE_3 KC_3 | 40 | #define DE_OSX_3 KC_3 |
| 44 | #define DE_4 KC_4 | 41 | #define DE_OSX_4 KC_4 |
| 45 | #define DE_5 KC_5 | 42 | #define DE_OSX_5 KC_5 |
| 46 | #define DE_6 KC_6 | 43 | #define DE_OSX_6 KC_6 |
| 47 | #define DE_7 KC_7 | 44 | #define DE_OSX_7 KC_7 |
| 48 | #define DE_8 KC_8 | 45 | #define DE_OSX_8 KC_8 |
| 49 | #define DE_9 KC_9 | 46 | #define DE_OSX_9 KC_9 |
| 50 | 47 | ||
| 51 | #define DE_DOT KC_DOT | 48 | #define DE_OSX_DOT KC_DOT |
| 52 | #define DE_COMM KC_COMM | 49 | #define DE_OSX_COMM KC_COMM |
| 53 | 50 | ||
| 54 | #define DE_SS KC_MINS | 51 | #define DE_OSX_SS KC_MINS |
| 55 | #define DE_AE KC_QUOT | 52 | #define DE_OSX_AE KC_QUOT |
| 56 | #define DE_UE KC_LBRC | 53 | #define DE_OSX_UE KC_LBRC |
| 57 | #define DE_OE KC_SCLN | 54 | #define DE_OSX_OE KC_SCLN |
| 58 | 55 | ||
| 59 | #define DE_CIRC KC_NUBS // accent circumflex ^ and ring ° | 56 | #define DE_OSX_CIRC KC_NUBS // accent circumflex ^ and ring ° |
| 60 | #define DE_ACUT KC_EQL // accent acute ´ and grave ` | 57 | #define DE_OSX_ACUT KC_EQL // accent acute ´ and grave ` |
| 61 | #define DE_PLUS KC_RBRC // + and * and ~ | 58 | #define DE_OSX_PLUS KC_RBRC // + and * and ~ |
| 62 | #define DE_HASH KC_BSLS // # and ' | 59 | #define DE_OSX_HASH KC_BSLS // # and ' |
| 63 | #define DE_LESS KC_GRV // < and > and | | 60 | #define DE_OSX_LESS KC_GRV // < and > and | |
| 64 | #define DE_MINS KC_SLSH // - and _ | 61 | #define DE_OSX_MINS KC_SLSH // - and _ |
| 65 | 62 | ||
| 66 | // shifted characters | 63 | // shifted characters |
| 67 | #define DE_RING LSFT(DE_CIRC) // ° | 64 | #define DE_OSX_RING LSFT(DE_OSX_CIRC) // ° |
| 68 | #define DE_EXLM LSFT(KC_1) // ! | 65 | #define DE_OSX_EXLM LSFT(KC_1) // ! |
| 69 | #define DE_DQOT LSFT(KC_2) // " | 66 | #define DE_OSX_DQOT LSFT(KC_2) // " |
| 70 | #define DE_PARA LSFT(KC_3) // § | 67 | #define DE_OSX_PARA LSFT(KC_3) // § |
| 71 | #define DE_DLR LSFT(KC_4) // $ | 68 | #define DE_OSX_DLR LSFT(KC_4) // $ |
| 72 | #define DE_PERC LSFT(KC_5) // % | 69 | #define DE_OSX_PERC LSFT(KC_5) // % |
| 73 | #define DE_AMPR LSFT(KC_6) // & | 70 | #define DE_OSX_AMPR LSFT(KC_6) // & |
| 74 | #define DE_SLSH LSFT(KC_7) // / | 71 | #define DE_OSX_SLSH LSFT(KC_7) // / |
| 75 | #define DE_LPRN LSFT(KC_8) // ( | 72 | #define DE_OSX_LPRN LSFT(KC_8) // ( |
| 76 | #define DE_RPRN LSFT(KC_9) // ) | 73 | #define DE_OSX_RPRN LSFT(KC_9) // ) |
| 77 | #define DE_EQL LSFT(KC_0) // = | 74 | #define DE_OSX_EQL LSFT(KC_0) // = |
| 78 | #define DE_QST LSFT(DE_SS) // ? | 75 | #define DE_OSX_QST LSFT(DE_OSX_SS) // ? |
| 79 | #define DE_GRV LSFT(DE_ACUT) // ` | 76 | #define DE_OSX_GRV LSFT(DE_OSX_ACUT) // ` |
| 80 | #define DE_ASTR LSFT(DE_PLUS) // * | 77 | #define DE_OSX_ASTR LSFT(DE_OSX_PLUS) // * |
| 81 | #define DE_QUOT LSFT(DE_HASH) // ' | 78 | #define DE_OSX_QUOT LSFT(DE_OSX_HASH) // ' |
| 82 | #define DE_MORE LSFT(DE_LESS) // > | 79 | #define DE_OSX_MORE LSFT(DE_OSX_LESS) // > |
| 83 | #define DE_COLN LSFT(KC_DOT) // : | 80 | #define DE_OSX_COLN LSFT(KC_DOT) // : |
| 84 | #define DE_SCLN LSFT(KC_COMM) // ; | 81 | #define DE_OSX_SCLN LSFT(KC_COMM) // ; |
| 85 | #define DE_UNDS LSFT(DE_MINS) // _ | 82 | #define DE_OSX_UNDS LSFT(DE_OSX_MINS) // _ |
| 86 | 83 | ||
| 87 | // Alt-ed characters | 84 | // Alt-ed characters |
| 88 | #define DE_SQ2 LALT(KC_2) // ² | 85 | //#define DE_OSX_SQ2 LALT(KC_2) // ² |
| 89 | #define DE_SQ3 LALT(KC_3) // ³ | 86 | //#define DE_OSX_SQ3 LALT(KC_3) // ³ |
| 90 | #define DE_LCBR LALT(KC_7) // { | 87 | #define DE_OSX_LCBR LALT(KC_8) // { |
| 91 | #define DE_LBRC LALT(KC_5) // [ | 88 | #define DE_OSX_LBRC LALT(KC_5) // [ |
| 92 | #define DE_RBRC LALT(KC_6) // ] | 89 | #define DE_OSX_RBRC LALT(KC_6) // ] |
| 93 | #define DE_RCBR LALT(KC_9) // } | 90 | #define DE_OSX_RCBR LALT(KC_9) // } |
| 94 | #define DE_BSLS LALT(LSFT(KC_7)) // backslash | 91 | #define DE_OSX_BSLS LALT(LSFT(KC_7)) // backslash |
| 95 | #define DE_AT LALT(DE_L) // @ | 92 | #define DE_OSX_AT LALT(DE_OSX_L) // @ |
| 96 | #define DE_EURO LALT(KC_E) // € | 93 | #define DE_OSX_EURO LALT(KC_E) // € |
| 97 | #define DE_TILD LALT(DE_N) // ~ | 94 | #define DE_OSX_TILD LALT(DE_OSX_N) // ~ |
| 98 | #define DE_PIPE LALT(DE_7) // | | 95 | #define DE_OSX_PIPE LALT(DE_OSX_7) // | |
| 99 | 96 | ||
| 100 | #endif | 97 | #endif |
diff --git a/quantum/keymap_extras/keymap_neo2.h b/quantum/keymap_extras/keymap_neo2.h index 055d7d0d1..80439af34 100644 --- a/quantum/keymap_extras/keymap_neo2.h +++ b/quantum/keymap_extras/keymap_neo2.h | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | #ifndef KEYMAP_NEO2 | 1 | #ifndef KEYMAP_NEO2 |
| 2 | #define KEYMAP_NEO2 | 2 | #define KEYMAP_NEO2 |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | #include "keymap_extras/keymap_german.h" | 5 | #include "keymap_german.h" |
| 6 | 6 | ||
| 7 | #define NEO_A KC_D | 7 | #define NEO_A KC_D |
| 8 | #define NEO_B KC_N | 8 | #define NEO_B KC_N |
| @@ -35,6 +35,25 @@ | |||
| 35 | #define NEO_UE DE_Y | 35 | #define NEO_UE DE_Y |
| 36 | #define NEO_SS DE_UE | 36 | #define NEO_SS DE_UE |
| 37 | 37 | ||
| 38 | #define NEO_DOT DE_DOT | ||
| 39 | #define NEO_COMM DE_COMM | ||
| 40 | |||
| 41 | #define NEO_1 DE_1 | ||
| 42 | #define NEO_2 DE_2 | ||
| 43 | #define NEO_3 DE_3 | ||
| 44 | #define NEO_4 DE_4 | ||
| 45 | #define NEO_5 DE_5 | ||
| 46 | #define NEO_6 DE_6 | ||
| 47 | #define NEO_7 DE_7 | ||
| 48 | #define NEO_8 DE_8 | ||
| 49 | #define NEO_9 DE_9 | ||
| 50 | #define NEO_0 DE_0 | ||
| 51 | #define NEO_MINS DE_SS | ||
| 52 | |||
| 53 | #define NEO_ACUT DE_PLUS | ||
| 54 | #define NEO_GRV DE_ACUT | ||
| 55 | #define NEO_CIRC DE_CIRC | ||
| 56 | |||
| 38 | #define NEO_L1_L KC_CAPS | 57 | #define NEO_L1_L KC_CAPS |
| 39 | #define NEO_L1_R DE_HASH | 58 | #define NEO_L1_R DE_HASH |
| 40 | 59 | ||
diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h index 7ef41fb79..da5c82975 100644 --- a/quantum/keymap_extras/keymap_nordic.h +++ b/quantum/keymap_extras/keymap_nordic.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | #ifndef KEYMAP_NORDIC_H | 1 | #ifndef KEYMAP_NORDIC_H |
| 2 | #define KEYMAP_NORDIC_H | 2 | #define KEYMAP_NORDIC_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Alt gr | 6 | // Alt gr |
| 7 | #define ALGR(kc) kc | 0x1400 | 7 | #define ALGR(kc) RALT(kc) |
| 8 | #define NO_ALGR KC_RALT | 8 | #define NO_ALGR KC_RALT |
| 9 | 9 | ||
| 10 | // Normal characters | 10 | // Normal characters |
| @@ -25,7 +25,7 @@ | |||
| 25 | #define NO_SECT LSFT(NO_HALF) | 25 | #define NO_SECT LSFT(NO_HALF) |
| 26 | #define NO_QUO2 LSFT(KC_2) | 26 | #define NO_QUO2 LSFT(KC_2) |
| 27 | #define NO_BULT LSFT(KC_4) | 27 | #define NO_BULT LSFT(KC_4) |
| 28 | #define NO_AMP LSFT(KC_6) | 28 | #define NO_AMPR LSFT(KC_6) |
| 29 | #define NO_SLSH LSFT(KC_7) | 29 | #define NO_SLSH LSFT(KC_7) |
| 30 | #define NO_LPRN LSFT(KC_8) | 30 | #define NO_LPRN LSFT(KC_8) |
| 31 | #define NO_RPRN LSFT(KC_9) | 31 | #define NO_RPRN LSFT(KC_9) |
diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h new file mode 100644 index 000000000..5c4e8c495 --- /dev/null +++ b/quantum/keymap_extras/keymap_norwegian.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef KEYMAP_NORWEGIAN_H | ||
| 2 | #define KEYMAP_NORWEGIAN_H | ||
| 3 | |||
| 4 | #include "keymap_nordic.h" | ||
| 5 | |||
| 6 | // There are slight differrences in the keyboards in the nordic contries | ||
| 7 | |||
| 8 | // Norwegian redifinitions from the nordic keyset | ||
| 9 | #undef NO_ACUT | ||
| 10 | #define NO_ACUT ALGR(NO_BSLS) // ´ | ||
| 11 | #undef NO_AE | ||
| 12 | #define NO_AE KC_QUOT // æ | ||
| 13 | #undef NO_BSLS | ||
| 14 | #define NO_BSLS KC_EQL // '\' | ||
| 15 | #undef NO_CIRC | ||
| 16 | #define NO_CIRC LSFT(KC_RBRC) // ^ | ||
| 17 | #undef NO_GRV | ||
| 18 | #define NO_GRV LSFT(NO_BSLS) // | ||
| 19 | #undef NO_OSLH | ||
| 20 | #define NO_OSLH KC_SCLN // ø | ||
| 21 | #undef NO_PIPE | ||
| 22 | #define NO_PIPE KC_GRV // | | ||
| 23 | |||
| 24 | // Additional norwegian keys not defined in the nordic keyset | ||
| 25 | #define NO_AA KC_LBRC // å | ||
| 26 | #define NO_ASTR LSFT(KC_BSLS) // * | ||
| 27 | |||
| 28 | // Norwegian unique MAC characters | ||
| 29 | #define NO_ACUT_MAC KC_EQL // = | ||
| 30 | #define NO_APOS_MAC KC_NUBS // ' | ||
| 31 | #define NO_AT_MAC KC_BSLS // @ | ||
| 32 | #define NO_BSLS_MAC ALGR(LSFT(KC_7)) // '\' | ||
| 33 | #define NO_DLR_MAC LSFT(KC_4) // $ | ||
| 34 | #define NO_GRV_MAC ALGR(NO_BSLS) // ` | ||
| 35 | #define NO_GRTR_MAC LSFT(KC_GRV) // > | ||
| 36 | #define NO_LCBR_MAC ALGR(LSFT(KC_8)) // } | ||
| 37 | #define NO_LESS_MAC KC_GRV // > | ||
| 38 | #define NO_PIPE_MAC ALGR(KC_7) // | | ||
| 39 | #define NO_RCBR_MAC ALGR(LSFT(KC_9)) // } | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_plover.h b/quantum/keymap_extras/keymap_plover.h new file mode 100644 index 000000000..9b88f7d84 --- /dev/null +++ b/quantum/keymap_extras/keymap_plover.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef KEYMAP_PLOVER_H | ||
| 2 | #define KEYMAP_PLOVER_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | #define PV_NUM KC_1 | ||
| 7 | #define PV_LS KC_Q | ||
| 8 | #define PV_LT KC_W | ||
| 9 | #define PV_LP KC_E | ||
| 10 | #define PV_LH KC_R | ||
| 11 | #define PV_LK KC_S | ||
| 12 | #define PV_LW KC_D | ||
| 13 | #define PV_LR KC_F | ||
| 14 | |||
| 15 | #define PV_STAR KC_Y | ||
| 16 | #define PV_RF KC_U | ||
| 17 | #define PV_RP KC_I | ||
| 18 | #define PV_RL KC_O | ||
| 19 | #define PV_RT KC_P | ||
| 20 | #define PV_RD KC_LBRC | ||
| 21 | #define PV_RR KC_J | ||
| 22 | #define PV_RB KC_K | ||
| 23 | #define PV_RG KC_L | ||
| 24 | #define PV_RS KC_SCLN | ||
| 25 | #define PV_RZ KC_QUOT | ||
| 26 | |||
| 27 | #define PV_A KC_C | ||
| 28 | #define PV_O KC_V | ||
| 29 | #define PV_E KC_N | ||
| 30 | #define PV_U KC_M | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_russian.h b/quantum/keymap_extras/keymap_russian.h new file mode 100644 index 000000000..237e9abde --- /dev/null +++ b/quantum/keymap_extras/keymap_russian.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #ifndef KEYMAP_RUSSIAN_H | ||
| 2 | #define KEYMAP_RUSSIAN_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Normal Chracters // reg SHIFT | ||
| 7 | #define RU_A KC_F // а and А | ||
| 8 | #define RU_BE KC_COMM // б and Б | ||
| 9 | #define RU_VE KC_D // в and В | ||
| 10 | #define RU_GHE KC_U // г and Г | ||
| 11 | #define RU_DE KC_L // д and Д | ||
| 12 | #define RU_IE KC_T // е and Е | ||
| 13 | #define RU_IO KC_GRV // ё and Ё | ||
| 14 | #define RU_ZHE KC_SCLN // ж and Ж | ||
| 15 | #define RU_ZE KC_P // з and З | ||
| 16 | #define RU_I KC_B // и and И | ||
| 17 | #define RU_SRT_I KC_Q // й and Й | ||
| 18 | #define RU_KA KC_R // к and К | ||
| 19 | #define RU_EL KC_K // л and Л | ||
| 20 | #define RU_EM KC_V // м and М | ||
| 21 | #define RU_EN KC_Y // н and Н | ||
| 22 | #define RU_O KC_J // о and О | ||
| 23 | #define RU_PE KC_G // п and П | ||
| 24 | #define RU_ER KC_H // р and Р | ||
| 25 | #define RU_ES KC_C // с and С | ||
| 26 | #define RU_TE KC_N // т and Т | ||
| 27 | #define RU_U KC_E // у and У | ||
| 28 | #define RU_EF KC_A // ф and Ф | ||
| 29 | #define RU_HA KC_LBRC // х and Х | ||
| 30 | #define RU_TSE KC_W // ц and Ц | ||
| 31 | #define RU_CHE KC_X // ч and Ч | ||
| 32 | #define RU_SHA KC_I // ш and Ш | ||
| 33 | #define RU_SHCHA KC_O // щ and Щ | ||
| 34 | #define RU_HSIGN KC_RBRC // ъ and Ъ | ||
| 35 | #define RU_YERU KC_S // ы and Ы | ||
| 36 | #define RU_SSIGN KC_M // ь and Ь | ||
| 37 | #define RU_E KC_QUOT // э and Э | ||
| 38 | #define RU_YU KC_DOT // ю and Ю | ||
| 39 | #define RU_YA KC_Z // я and Я | ||
| 40 | |||
| 41 | #define RU_1 KC_1 // 1 and ! | ||
| 42 | #define RU_2 KC_2 // 2 and " | ||
| 43 | #define RU_3 KC_3 // 3 and № | ||
| 44 | #define RU_4 KC_4 // 4 and ; | ||
| 45 | #define RU_5 KC_5 // 5 and % | ||
| 46 | #define RU_6 KC_6 // 6 and : | ||
| 47 | #define RU_7 KC_7 // 7 and ? | ||
| 48 | #define RU_8 KC_8 // 8 and * | ||
| 49 | #define RU_9 KC_9 // 9 and ( | ||
| 50 | #define RU_0 KC_0 // 0 and ) | ||
| 51 | |||
| 52 | #define RU_MINS KC_MINS // - and _ | ||
| 53 | #define RU_EQL KC_EQL // = and + | ||
| 54 | #define RU_BSLS KC_BSLS // \ and / | ||
| 55 | #define RU_DOT KC_SLSH // . and , | ||
| 56 | |||
| 57 | // Shifted Chracters | ||
| 58 | #define RU_EXLM LSFT(RU_1) // ! | ||
| 59 | #define RU_DQUT LSFT(RU_2) // " | ||
| 60 | #define RU_NMRO LSFT(RU_3) // № | ||
| 61 | #define RU_SCLN LSFT(RU_4) // ; | ||
| 62 | #define RU_PERC LSFT(RU_5) // % | ||
| 63 | #define RU_COLN LSFT(RU_6) // : | ||
| 64 | #define RU_QUES LSFT(RU_7) // ? | ||
| 65 | #define RU_ASTR LSFT(RU_8) // * | ||
| 66 | #define RU_LPRN LSFT(RU_9) // ( | ||
| 67 | #define RU_RPRN LSFT(RU_0) // ) | ||
| 68 | |||
| 69 | #define RU_UNDR LSFT(RU_MINS) // _ | ||
| 70 | #define RU_PLUS LSFT(RU_EQL) // + | ||
| 71 | #define RU_SLSH LSFT(RU_BSLS) // / | ||
| 72 | #define RU_COMM LSFT(RU_DOT) // , | ||
| 73 | |||
| 74 | // Alt Gr-ed characters | ||
| 75 | #define RU_RUBL RALT(RU_8) // ₽ | ||
| 76 | |||
| 77 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_spanish.h b/quantum/keymap_extras/keymap_spanish.h index 7f980afbc..4ba568af2 100644 --- a/quantum/keymap_extras/keymap_spanish.h +++ b/quantum/keymap_extras/keymap_spanish.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | #ifndef KEYMAP_SPANISH_H | 1 | #ifndef KEYMAP_SPANISH_H |
| 2 | #define KEYMAP_SPANISH_H | 2 | #define KEYMAP_SPANISH_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Alt gr | 6 | // Alt gr |
| 7 | #define ALGR(kc) kc | 0x1400 | 7 | #define ALGR(kc) RALT(kc) |
| 8 | #define NO_ALGR KC_RALT | 8 | #define NO_ALGR KC_RALT |
| 9 | 9 | ||
| 10 | // Normal characters | 10 | // Normal characters |
| @@ -49,7 +49,7 @@ | |||
| 49 | #define ES_PIPE ALGR(KC_1) | 49 | #define ES_PIPE ALGR(KC_1) |
| 50 | #define ES_AT ALGR(KC_2) | 50 | #define ES_AT ALGR(KC_2) |
| 51 | #define ES_HASH ALGR(KC_3) | 51 | #define ES_HASH ALGR(KC_3) |
| 52 | #define ES_TILD ALGR(KC_4) | 52 | #define ES_TILD ALGR(ES_NTIL) |
| 53 | #define ES_EURO ALGR(KC_5) | 53 | #define ES_EURO ALGR(KC_5) |
| 54 | #define ES_NOT ALGR(KC_6) | 54 | #define ES_NOT ALGR(KC_6) |
| 55 | 55 | ||
| @@ -59,4 +59,4 @@ | |||
| 59 | #define ES_LCBR ALGR(ES_ACUT) | 59 | #define ES_LCBR ALGR(ES_ACUT) |
| 60 | #define ES_RCRB ALGR(ES_CCED) | 60 | #define ES_RCRB ALGR(ES_CCED) |
| 61 | 61 | ||
| 62 | #endif \ No newline at end of file | 62 | #endif |
diff --git a/quantum/keymap_extras/keymap_uk.h b/quantum/keymap_extras/keymap_uk.h index 5b4bd3c0d..00c87afc3 100644 --- a/quantum/keymap_extras/keymap_uk.h +++ b/quantum/keymap_extras/keymap_uk.h | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | #ifndef KEYMAP_UK_H | 1 | #ifndef KEYMAP_UK_H |
| 2 | #define KEYMAP_UK_H | 2 | #define KEYMAP_UK_H |
| 3 | 3 | ||
| 4 | #include "keymap_common.h" | 4 | #include "keymap.h" |
| 5 | 5 | ||
| 6 | // Alt gr | 6 | // Alt gr |
| 7 | #define ALGR(kc) kc | 0x1400 | 7 | #define ALGR(kc) RALT(kc) |
| 8 | #define NO_ALGR KC_RALT | 8 | #define NO_ALGR KC_RALT |
| 9 | 9 | ||
| 10 | // Normal characters | 10 | // Normal characters |
| @@ -33,4 +33,4 @@ | |||
| 33 | 33 | ||
| 34 | #define UK_AACT ALGR(KC_A) | 34 | #define UK_AACT ALGR(KC_A) |
| 35 | 35 | ||
| 36 | #endif \ No newline at end of file | 36 | #endif |
diff --git a/quantum/keymap_extras/keymap_unicode_cyrillic.h b/quantum/keymap_extras/keymap_unicode_cyrillic.h new file mode 100644 index 000000000..a40626d91 --- /dev/null +++ b/quantum/keymap_extras/keymap_unicode_cyrillic.h | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | #ifndef KEYMAP_CYRILLIC_H | ||
| 2 | #define KEYMAP_CYRILLIC_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | /* | ||
| 7 | * This is based off of | ||
| 8 | * https://en.wikipedia.org/wiki/Cyrillic_script | ||
| 9 | * | ||
| 10 | * Unicode is iffy, a software implementation is preferred | ||
| 11 | */ | ||
| 12 | |||
| 13 | // Capital Char russian/ukrainian/bulgarian | ||
| 14 | #define CY_A UC(0x0410) // А rus ukr bul | ||
| 15 | #define CY_BE UC(0x0411) // Б rus ukr bul | ||
| 16 | #define CY_VE UC(0x0412) // В rus ukr bul | ||
| 17 | #define CY_GHE UC(0x0413) // Г rus ukr bul | ||
| 18 | #define CY_GHEUP UC(0x0490) // Ґ ukr | ||
| 19 | #define CY_DE UC(0x0414) // Д rus ukr bul | ||
| 20 | #define CY_DJE UC(0x0402) // Ђ | ||
| 21 | #define CY_GJE UC(0x0403) // Ѓ | ||
| 22 | #define CY_IE UC(0x0415) // Е rus ukr bul | ||
| 23 | #define CY_IO UC(0x0401) // Ё rus | ||
| 24 | #define CY_UIE UC(0x0404) // Є ukr | ||
| 25 | #define CY_ZHE UC(0x0416) // Ж rus ukr bul | ||
| 26 | #define CY_ZE UC(0x0417) // З rus ukr bul | ||
| 27 | #define CY_DZE UC(0x0405) // Ѕ | ||
| 28 | #define CY_I UC(0x0418) // И rus ukr bul | ||
| 29 | #define CY_B_U_I UC(0x0406) // І ukr | ||
| 30 | #define CY_YI UC(0x0407) // Ї ukr | ||
| 31 | #define CY_SRT_I UC(0x0419) // Й rus ukr bul | ||
| 32 | #define CY_JE UC(0x0408) // Ј | ||
| 33 | #define CY_KA UC(0x041a) // К rus ukr bul | ||
| 34 | #define CY_EL UC(0x041b) // Л rus ukr bul | ||
| 35 | #define CY_LJE UC(0x0409) // Љ | ||
| 36 | #define CY_EM UC(0x041c) // М rus ukr bul | ||
| 37 | #define CY_EN UC(0x041d) // Н rus ukr bul | ||
| 38 | #define CY_NJE UC(0x040a) // Њ | ||
| 39 | #define CY_O UC(0x041e) // О rus ukr bul | ||
| 40 | #define CY_PE UC(0x041f) // П rus ukr bul | ||
| 41 | #define CY_ER UC(0x0420) // Р rus ukr bul | ||
| 42 | #define CY_ES UC(0x0421) // С rus ukr bul | ||
| 43 | #define CY_TE UC(0x0422) // Т rus ukr bul | ||
| 44 | #define CY_TSHE UC(0x040b) // Ћ | ||
| 45 | #define CY_KJE UC(0x040c) // Ќ | ||
| 46 | #define CY_U UC(0x0423) // У rus ukr bul | ||
| 47 | #define CY_SRT_U UC(0x040e) // Ў | ||
| 48 | #define CY_EF UC(0x0424) // Ф rus ukr bul | ||
| 49 | #define CY_HA UC(0x0425) // Х rus bul | ||
| 50 | #define CY_TSE UC(0x0426) // Ц rus ukr bul | ||
| 51 | #define CY_CHE UC(0x0427) // Ч rus ukr bul | ||
| 52 | #define CY_DZHE UC(0x040f) // Џ | ||
| 53 | #define CY_SHA UC(0x0428) // Ш rus ukr bul | ||
| 54 | #define CY_SHCHA UC(0x0429) // Щ rus ukr bul | ||
| 55 | #define CY_HSIGN UC(0x042a) // Ъ rus bul | ||
| 56 | #define CY_YERU UC(0x042b) // Ы rus | ||
| 57 | #define CY_SSIGN UC(0x042c) // Ь rus ukr bul | ||
| 58 | #define CY_E UC(0x042d) // Э rus | ||
| 59 | #define CY_YU UC(0x042e) // Ю rus ukr bul | ||
| 60 | #define CY_YA UC(0x042f) // Я rus ukr bul | ||
| 61 | // Important Cyrillic non-Slavic letters | ||
| 62 | #define CY_PALOCHKA UC(0x04c0) // Ӏ | ||
| 63 | #define CY_SCHWA UC(0x04d8) // Ә | ||
| 64 | #define CY_GHE_S UC(0x0492) // Ғ | ||
| 65 | #define CY_ZE_D UC(0x0498) // Ҙ | ||
| 66 | #define CY_ES_D UC(0x04aa) // Ҫ | ||
| 67 | #define CY_BR_KA UC(0x04a0) // Ҡ | ||
| 68 | #define CY_ZHE_D UC(0x0496) // Җ | ||
| 69 | #define CY_KA_D UC(0x049a) // Қ | ||
| 70 | #define CY_EN_D UC(0x04a2) // Ң | ||
| 71 | #define CY_ENGHE UC(0x04a4) // Ҥ | ||
| 72 | #define CY_BRD_O UC(0x04e8) // Ө | ||
| 73 | #define CY_STR_U UC(0x04ae) // Ү | ||
| 74 | #define CY_S_U_S UC(0x04b0) // Ұ | ||
| 75 | #define CY_SHHA UC(0x04ba) // Һ | ||
| 76 | #define CY_HA_D UC(0x04b2) // Ҳ | ||
| 77 | |||
| 78 | |||
| 79 | // Small | ||
| 80 | #define CY_a UC(0x0430) // a rus ukr bul | ||
| 81 | #define CY_be UC(0x0431) // б rus ukr bul | ||
| 82 | #define CY_ve UC(0x0432) // в rus ukr bul | ||
| 83 | #define CY_ghe UC(0x0433) // г rus ukr bul | ||
| 84 | #define CY_gheup UC(0x0491) // ґ ukr | ||
| 85 | #define CY_de UC(0x0434) // д rus ukr bul | ||
| 86 | #define CY_dje UC(0x0452) // ђ | ||
| 87 | #define CY_gje UC(0x0453) // ѓ | ||
| 88 | #define CY_ie UC(0x0435) // е rus ukr bul | ||
| 89 | #define CY_io UC(0x0451) // ё rus | ||
| 90 | #define CY_uie UC(0x0454) // є ukr | ||
| 91 | #define CY_zhe UC(0x0436) // ж rus ukr bul | ||
| 92 | #define CY_ze UC(0x0437) // з rus ukr bul | ||
| 93 | #define CY_dze UC(0x0455) // ѕ | ||
| 94 | #define CY_i UC(0x0438) // и rus ukr bul | ||
| 95 | #define CY_b_u_i UC(0x0456) // і ukr | ||
| 96 | #define CY_yi UC(0x0457) // ї ukr | ||
| 97 | #define CY_srt_i UC(0x0439) // й rus ukr bul | ||
| 98 | #define CY_je UC(0x0458) // ј | ||
| 99 | #define CY_ka UC(0x043a) // к rus ukr bul | ||
| 100 | #define CY_el UC(0x043b) // л rus ukr bul | ||
| 101 | #define CY_lje UC(0x0459) // љ | ||
| 102 | #define CY_em UC(0x043c) // м rus ukr bul | ||
| 103 | #define CY_en UC(0x043d) // н rus ukr bul | ||
| 104 | #define CY_nje UC(0x045a) // њ | ||
| 105 | #define CY_o UC(0x043e) // о rus ukr bul | ||
| 106 | #define CY_pe UC(0x043f) // п rus ukr bul | ||
| 107 | #define CY_er UC(0x0440) // р rus ukr bul | ||
| 108 | #define CY_es UC(0x0441) // с rus ukr bul | ||
| 109 | #define CY_te UC(0x0442) // т rus ukr bul | ||
| 110 | #define CY_tshe UC(0x045b) // ћ | ||
| 111 | #define CY_kje UC(0x045c) // ќ | ||
| 112 | #define CY_u UC(0x0443) // у rus ukr bul | ||
| 113 | #define CY_srt_u UC(0x045e) // ў | ||
| 114 | #define CY_ef UC(0x0444) // ф rus ukr bul | ||
| 115 | #define CY_ha UC(0x0445) // х rus ukr bul | ||
| 116 | #define CY_tse UC(0x0446) // ц rus ukr bul | ||
| 117 | #define CY_che UC(0x0447) // ч rus ukr bul | ||
| 118 | #define CY_dzhe UC(0x045f) // џ | ||
| 119 | #define CY_sha UC(0x0448) // ш rus ukr bul | ||
| 120 | #define CY_shcha UC(0x0449) // щ rus ukr bul | ||
| 121 | #define CY_hsign UC(0x044a) // ъ rus bul | ||
| 122 | #define CY_yeru UC(0x044b) // ы rus | ||
| 123 | #define CY_ssign UC(0x044c) // ь rus ukr bul | ||
| 124 | #define CY_e UC(0x044d) // э rus | ||
| 125 | #define CY_yu UC(0x044e) // ю rus ukr bul | ||
| 126 | #define CY_ya UC(0x044f) // я rus ukr bul | ||
| 127 | // Important Cyrillic non-Slavic letters | ||
| 128 | #define CY_palochka UC(0x04cf) // ӏ | ||
| 129 | #define CY_schwa UC(0x04d9) // ә | ||
| 130 | #define CY_ghe_s UC(0x0493) // ғ | ||
| 131 | #define CY_ze_d UC(0x0499) // ҙ | ||
| 132 | #define CY_es_d UC(0x04ab) // ҫ | ||
| 133 | #define CY_br_ka UC(0x04a1) // ҡ | ||
| 134 | #define CY_zhe_d UC(0x0497) // җ | ||
| 135 | #define CY_ka_d UC(0x049b) // қ | ||
| 136 | #define CY_en_d UC(0x04a3) // ң | ||
| 137 | #define CY_enghe UC(0x04a5) // ҥ | ||
| 138 | #define CY_brd_o UC(0x04e9) // ө | ||
| 139 | #define CY_str_u UC(0x04af) // ү | ||
| 140 | #define CY_s_u_s UC(0x04b1) // ұ | ||
| 141 | #define CY_shha UC(0x04bb) // һ | ||
| 142 | #define CY_ha_d UC(0x04b3) // ҳ | ||
| 143 | |||
| 144 | |||
| 145 | // Extra | ||
| 146 | #define CY_slr_ve UC(0x1c80) // ᲀ CYRILLIC SMALL LETTER ROUNDED VE | ||
| 147 | #define CY_ll_de UC(0x1c81) // ᲁ CYRILLIC SMALL LETTER LONG-LEGGED DE | ||
| 148 | #define CY_ZEMLYA UC(0xa640) // Ꙁ CYRILLIC CAPITAL LETTER ZEMLYA | ||
| 149 | #define CY_zemlya UC(0xa641) // ꙁ CYRILLIC SMALL LETTER ZEMLYA | ||
| 150 | #define CY_RV_DZE UC(0xa644) // Ꙅ CYRILLIC CAPITAL LETTER REVERSED DZE | ||
| 151 | #define CY_rv_DZE UC(0xa645) // ꙅ CYRILLIC SMALL LETTER REVERSED DZE | ||
| 152 | #define CY_slw_es UC(0x1c83) // ᲃ CYRILLIC SMALL LETTER WIDE ES | ||
| 153 | #define CY_st_te UC(0x1c84) // ᲄ CYRILLIC SMALL LETTER TALL TE | ||
| 154 | #define CY_3l_te UC(0x1c85) // ᲅ CYRILLIC SMALL LETTER THREE-LEGGED TE | ||
| 155 | #define CY_thsign UC(0x1c86) // ᲆ CYRILLIC SMALL LETTER TALL HARD SIGN | ||
| 156 | #define CY_YERUBY UC(0xa650) // Ꙑ CYRILLIC CAPITAL LETTER YERU WITH BACK YER | ||
| 157 | #define CY_yeruby UC(0xa651) // ꙑ CYRILLIC SMALL LETTER YERU WITH BACK YER | ||
| 158 | #define CY_RUBL UC(0x20bd) // ₽ | ||
| 159 | #define CY_NMRO UC(0x2116) // № | ||
| 160 | |||
| 161 | // The letters Zje and Sje are made for other letters and accent marks | ||
| 162 | |||
| 163 | #endif | ||
diff --git a/quantum/keymap_midi.c b/quantum/keymap_midi.c deleted file mode 100644 index e37ea3103..000000000 --- a/quantum/keymap_midi.c +++ /dev/null | |||
| @@ -1,109 +0,0 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2015 Jack Humbert <jack.humb@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_common.h" | ||
| 19 | #include "keymap_midi.h" | ||
| 20 | |||
| 21 | uint8_t starting_note = 0x0C; | ||
| 22 | int offset = 7; | ||
| 23 | |||
| 24 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 25 | { | ||
| 26 | if (id != 0) { | ||
| 27 | if (record->event.pressed) { | ||
| 28 | midi_send_noteon(&midi_device, opt, (id & 0xFF), 127); | ||
| 29 | } else { | ||
| 30 | midi_send_noteoff(&midi_device, opt, (id & 0xFF), 127); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) { | ||
| 35 | if (record->event.pressed) { | ||
| 36 | starting_note++; | ||
| 37 | play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1)), 0xC); | ||
| 38 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 39 | midi_send_cc(&midi_device, 1, 0x7B, 0); | ||
| 40 | midi_send_cc(&midi_device, 2, 0x7B, 0); | ||
| 41 | midi_send_cc(&midi_device, 3, 0x7B, 0); | ||
| 42 | midi_send_cc(&midi_device, 4, 0x7B, 0); | ||
| 43 | return; | ||
| 44 | } else { | ||
| 45 | stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1))); | ||
| 46 | stop_all_notes(); | ||
| 47 | return; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) { | ||
| 51 | if (record->event.pressed) { | ||
| 52 | starting_note--; | ||
| 53 | play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1)), 0xC); | ||
| 54 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 55 | midi_send_cc(&midi_device, 1, 0x7B, 0); | ||
| 56 | midi_send_cc(&midi_device, 2, 0x7B, 0); | ||
| 57 | midi_send_cc(&midi_device, 3, 0x7B, 0); | ||
| 58 | midi_send_cc(&midi_device, 4, 0x7B, 0); | ||
| 59 | return; | ||
| 60 | } else { | ||
| 61 | stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[0 + offset])/12.0+(MATRIX_ROWS - 1))); | ||
| 62 | stop_all_notes(); | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { | ||
| 68 | offset++; | ||
| 69 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 70 | midi_send_cc(&midi_device, 1, 0x7B, 0); | ||
| 71 | midi_send_cc(&midi_device, 2, 0x7B, 0); | ||
| 72 | midi_send_cc(&midi_device, 3, 0x7B, 0); | ||
| 73 | midi_send_cc(&midi_device, 4, 0x7B, 0); | ||
| 74 | stop_all_notes(); | ||
| 75 | for (int i = 0; i <= 7; i++) { | ||
| 76 | play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1)), 0xC); | ||
| 77 | _delay_us(80000); | ||
| 78 | stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1))); | ||
| 79 | _delay_us(8000); | ||
| 80 | } | ||
| 81 | return; | ||
| 82 | } | ||
| 83 | if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { | ||
| 84 | offset--; | ||
| 85 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 86 | midi_send_cc(&midi_device, 1, 0x7B, 0); | ||
| 87 | midi_send_cc(&midi_device, 2, 0x7B, 0); | ||
| 88 | midi_send_cc(&midi_device, 3, 0x7B, 0); | ||
| 89 | midi_send_cc(&midi_device, 4, 0x7B, 0); | ||
| 90 | stop_all_notes(); | ||
| 91 | for (int i = 0; i <= 7; i++) { | ||
| 92 | play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1)), 0xC); | ||
| 93 | _delay_us(80000); | ||
| 94 | stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[i + offset])/12.0+(MATRIX_ROWS - 1))); | ||
| 95 | _delay_us(8000); | ||
| 96 | } | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (record->event.pressed) { | ||
| 101 | // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127); | ||
| 102 | midi_send_noteon(&midi_device, 0, (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row), 127); | ||
| 103 | play_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)), 0xF); | ||
| 104 | } else { | ||
| 105 | // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127); | ||
| 106 | midi_send_noteoff(&midi_device, 0, (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row), 127); | ||
| 107 | stop_note(((double)261.626)*pow(2.0, -1.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row))); | ||
| 108 | } | ||
| 109 | } \ No newline at end of file | ||
diff --git a/quantum/keymap_unicode.c b/quantum/keymap_unicode.c deleted file mode 100644 index a44965e61..000000000 --- a/quantum/keymap_unicode.c +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2015 Jack Humbert <jack.humb@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_common.h" | ||
| 19 | |||
| 20 | uint16_t hextokeycode(int hex) { | ||
| 21 | if (hex == 0x0) { | ||
| 22 | return KC_0; | ||
| 23 | } else if (hex < 0xA) { | ||
| 24 | return KC_1 + (hex - 0x1); | ||
| 25 | } else { | ||
| 26 | return KC_A + (hex - 0xA); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 31 | { | ||
| 32 | |||
| 33 | // For more info on how this works per OS, see here: https://en.wikipedia.org/wiki/Unicode_input#Hexadecimal_code_input | ||
| 34 | |||
| 35 | if (record->event.pressed) { | ||
| 36 | uint16_t unicode = (opt << 8) | id; | ||
| 37 | register_code(KC_LALT); | ||
| 38 | |||
| 39 | register_code(hextokeycode((unicode & 0xF000) >> 12)); | ||
| 40 | unregister_code(hextokeycode((unicode & 0xF000) >> 12)); | ||
| 41 | register_code(hextokeycode((unicode & 0x0F00) >> 8)); | ||
| 42 | unregister_code(hextokeycode((unicode & 0x0F00) >> 8)); | ||
| 43 | register_code(hextokeycode((unicode & 0x00F0) >> 4)); | ||
| 44 | unregister_code(hextokeycode((unicode & 0x00F0) >> 4)); | ||
| 45 | register_code(hextokeycode((unicode & 0x000F))); | ||
| 46 | unregister_code(hextokeycode((unicode & 0x000F))); | ||
| 47 | |||
| 48 | /* Test 'a' */ | ||
| 49 | // register_code(hextokeycode(0x0)); | ||
| 50 | // unregister_code(hextokeycode(0x0)); | ||
| 51 | // register_code(hextokeycode(0x0)); | ||
| 52 | // unregister_code(hextokeycode(0x0)); | ||
| 53 | // register_code(hextokeycode(0x6)); | ||
| 54 | // unregister_code(hextokeycode(0x6)); | ||
| 55 | // register_code(hextokeycode(0x1)); | ||
| 56 | // unregister_code(hextokeycode(0x1)); | ||
| 57 | |||
| 58 | unregister_code(KC_LALT); | ||
| 59 | } | ||
| 60 | return; | ||
| 61 | } \ No newline at end of file | ||
diff --git a/quantum/led.c b/quantum/led.c deleted file mode 100644 index 2c0574660..000000000 --- a/quantum/led.c +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | /* | ||
| 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 | #include <avr/io.h> | ||
| 19 | #include "stdint.h" | ||
| 20 | #include "led.h" | ||
| 21 | |||
| 22 | |||
| 23 | void led_set(uint8_t usb_led) | ||
| 24 | { | ||
| 25 | // // Using PE6 Caps Lock LED | ||
| 26 | // if (usb_led & (1<<USB_LED_CAPS_LOCK)) | ||
| 27 | // { | ||
| 28 | // // Output high. | ||
| 29 | // DDRE |= (1<<6); | ||
| 30 | // PORTE |= (1<<6); | ||
| 31 | // } | ||
| 32 | // else | ||
| 33 | // { | ||
| 34 | // // Output low. | ||
| 35 | // DDRE &= ~(1<<6); | ||
| 36 | // PORTE &= ~(1<<6); | ||
| 37 | // } | ||
| 38 | } | ||
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c index f20043067..401845e85 100755 --- a/quantum/light_ws2812.c +++ b/quantum/light_ws2812.c | |||
| @@ -19,12 +19,16 @@ | |||
| 19 | // Setleds for standard RGB | 19 | // Setleds for standard RGB |
| 20 | void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) | 20 | void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) |
| 21 | { | 21 | { |
| 22 | ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); | 22 | // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); |
| 23 | ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF)); | ||
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) | 26 | void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) |
| 26 | { | 27 | { |
| 27 | ws2812_DDRREG |= pinmask; // Enable DDR | 28 | // ws2812_DDRREG |= pinmask; // Enable DDR |
| 29 | // new universal format (DDR) | ||
| 30 | _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask; | ||
| 31 | |||
| 28 | ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); | 32 | ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); |
| 29 | _delay_us(50); | 33 | _delay_us(50); |
| 30 | } | 34 | } |
| @@ -32,14 +36,17 @@ void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pin | |||
| 32 | // Setleds for SK6812RGBW | 36 | // Setleds for SK6812RGBW |
| 33 | void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) | 37 | void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) |
| 34 | { | 38 | { |
| 35 | ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR | 39 | // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR |
| 36 | ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin)); | 40 | // new universal format (DDR) |
| 41 | _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF); | ||
| 42 | |||
| 43 | ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF)); | ||
| 37 | _delay_us(80); | 44 | _delay_us(80); |
| 38 | } | 45 | } |
| 39 | 46 | ||
| 40 | void ws2812_sendarray(uint8_t *data,uint16_t datlen) | 47 | void ws2812_sendarray(uint8_t *data,uint16_t datlen) |
| 41 | { | 48 | { |
| 42 | ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin)); | 49 | ws2812_sendarray_mask(data,datlen,_BV(RGB_DI_PIN & 0xF)); |
| 43 | } | 50 | } |
| 44 | 51 | ||
| 45 | /* | 52 | /* |
| @@ -108,8 +115,10 @@ void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) | |||
| 108 | uint8_t curbyte,ctr,masklo; | 115 | uint8_t curbyte,ctr,masklo; |
| 109 | uint8_t sreg_prev; | 116 | uint8_t sreg_prev; |
| 110 | 117 | ||
| 111 | masklo =~maskhi&ws2812_PORTREG; | 118 | // masklo =~maskhi&ws2812_PORTREG; |
| 112 | maskhi |= ws2812_PORTREG; | 119 | // maskhi |= ws2812_PORTREG; |
| 120 | masklo =~maskhi&_SFR_IO8((RGB_DI_PIN >> 4) + 2); | ||
| 121 | maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2); | ||
| 113 | sreg_prev=SREG; | 122 | sreg_prev=SREG; |
| 114 | cli(); | 123 | cli(); |
| 115 | 124 | ||
| @@ -173,7 +182,7 @@ w_nop16 | |||
| 173 | " dec %0 \n\t" // '1' [+2] '0' [+2] | 182 | " dec %0 \n\t" // '1' [+2] '0' [+2] |
| 174 | " brne loop%=\n\t" // '1' [+3] '0' [+4] | 183 | " brne loop%=\n\t" // '1' [+3] '0' [+4] |
| 175 | : "=&d" (ctr) | 184 | : "=&d" (ctr) |
| 176 | : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo) | 185 | : "r" (curbyte), "I" (_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r" (maskhi), "r" (masklo) |
| 177 | ); | 186 | ); |
| 178 | } | 187 | } |
| 179 | 188 | ||
diff --git a/quantum/matrix.c b/quantum/matrix.c index 95bf4c097..3174e0739 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright 2012 Jun Wako | 2 | Copyright 2012 Jun Wako |
| 3 | Generated by planckkeyboard.com (2014 Jack Humbert) | 3 | Copyright 2014 Jack Humbert |
| 4 | 4 | ||
| 5 | This program is free software: you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published by |
| @@ -15,23 +15,26 @@ GNU General Public License for more details. | |||
| 15 | You should have received a copy of the GNU General Public License | 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/>. | 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | */ | 17 | */ |
| 18 | |||
| 19 | /* | ||
| 20 | * scan matrix | ||
| 21 | */ | ||
| 22 | #include <stdint.h> | 18 | #include <stdint.h> |
| 23 | #include <stdbool.h> | 19 | #include <stdbool.h> |
| 20 | #if defined(__AVR__) | ||
| 24 | #include <avr/io.h> | 21 | #include <avr/io.h> |
| 25 | #include <util/delay.h> | 22 | #endif |
| 23 | #include "wait.h" | ||
| 26 | #include "print.h" | 24 | #include "print.h" |
| 27 | #include "debug.h" | 25 | #include "debug.h" |
| 28 | #include "util.h" | 26 | #include "util.h" |
| 29 | #include "matrix.h" | 27 | #include "matrix.h" |
| 30 | 28 | ||
| 31 | #ifndef DEBOUNCE | 29 | /* Set 0 if debouncing isn't needed */ |
| 32 | # define DEBOUNCE 10 | 30 | |
| 31 | #ifndef DEBOUNCING_DELAY | ||
| 32 | # define DEBOUNCING_DELAY 5 | ||
| 33 | #endif | 33 | #endif |
| 34 | static uint8_t debouncing = DEBOUNCE; | 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; | ||
| 35 | 38 | ||
| 36 | /* matrix state(1:on, 0:off) */ | 39 | /* matrix state(1:on, 0:off) */ |
| 37 | static matrix_row_t matrix[MATRIX_ROWS]; | 40 | static matrix_row_t matrix[MATRIX_ROWS]; |
| @@ -42,39 +45,85 @@ static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | |||
| 42 | static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS]; | 45 | static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS]; |
| 43 | #endif | 46 | #endif |
| 44 | 47 | ||
| 48 | #if MATRIX_COLS > 16 | ||
| 49 | #define SHIFTER 1UL | ||
| 50 | #else | ||
| 51 | #define SHIFTER 1 | ||
| 52 | #endif | ||
| 53 | |||
| 45 | static matrix_row_t read_cols(void); | 54 | static matrix_row_t read_cols(void); |
| 46 | static void init_cols(void); | 55 | static void init_cols(void); |
| 47 | static void unselect_rows(void); | 56 | static void unselect_rows(void); |
| 48 | static void select_row(uint8_t row); | 57 | static void select_row(uint8_t row); |
| 49 | 58 | ||
| 50 | __attribute__ ((weak)) | 59 | __attribute__ ((weak)) |
| 51 | void * matrix_init_kb(void) { | 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 | } | ||
| 52 | 68 | ||
| 53 | }; | 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 | } | ||
| 54 | 78 | ||
| 55 | __attribute__ ((weak)) | 79 | __attribute__ ((weak)) |
| 56 | void * matrix_scan_kb(void) { | 80 | void matrix_init_user(void) { |
| 81 | } | ||
| 57 | 82 | ||
| 58 | }; | 83 | __attribute__ ((weak)) |
| 84 | void matrix_scan_user(void) { | ||
| 85 | } | ||
| 59 | 86 | ||
| 60 | inline | 87 | inline |
| 61 | uint8_t matrix_rows(void) | 88 | uint8_t matrix_rows(void) { |
| 62 | { | ||
| 63 | return MATRIX_ROWS; | 89 | return MATRIX_ROWS; |
| 64 | } | 90 | } |
| 65 | 91 | ||
| 66 | inline | 92 | inline |
| 67 | uint8_t matrix_cols(void) | 93 | uint8_t matrix_cols(void) { |
| 68 | { | ||
| 69 | return MATRIX_COLS; | 94 | return MATRIX_COLS; |
| 70 | } | 95 | } |
| 71 | 96 | ||
| 72 | void matrix_init(void) | 97 | // void matrix_power_up(void) { |
| 73 | { | 98 | // #if DIODE_DIRECTION == COL2ROW |
| 99 | // for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { | ||
| 100 | // /* DDRxn */ | ||
| 101 | // _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF); | ||
| 102 | // toggle_row(r); | ||
| 103 | // } | ||
| 104 | // for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { | ||
| 105 | // /* PORTxn */ | ||
| 106 | // _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF); | ||
| 107 | // } | ||
| 108 | // #else | ||
| 109 | // for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { | ||
| 110 | // /* DDRxn */ | ||
| 111 | // _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF); | ||
| 112 | // toggle_col(c); | ||
| 113 | // } | ||
| 114 | // for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { | ||
| 115 | // /* PORTxn */ | ||
| 116 | // _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF); | ||
| 117 | // } | ||
| 118 | // #endif | ||
| 119 | // } | ||
| 120 | |||
| 121 | void matrix_init(void) { | ||
| 74 | // To use PORTF disable JTAG with writing JTD bit twice within four cycles. | 122 | // To use PORTF disable JTAG with writing JTD bit twice within four cycles. |
| 75 | MCUCR |= (1<<JTD); | 123 | #ifdef __AVR_ATmega32U4__ |
| 76 | MCUCR |= (1<<JTD); | 124 | MCUCR |= _BV(JTD); |
| 77 | 125 | MCUCR |= _BV(JTD); | |
| 126 | #endif | ||
| 78 | 127 | ||
| 79 | // initialize row and col | 128 | // initialize row and col |
| 80 | unselect_rows(); | 129 | unselect_rows(); |
| @@ -86,33 +135,30 @@ void matrix_init(void) | |||
| 86 | matrix_debouncing[i] = 0; | 135 | matrix_debouncing[i] = 0; |
| 87 | } | 136 | } |
| 88 | 137 | ||
| 89 | if (matrix_init_kb) { | 138 | matrix_init_quantum(); |
| 90 | (*matrix_init_kb)(); | ||
| 91 | } | ||
| 92 | } | 139 | } |
| 93 | 140 | ||
| 94 | |||
| 95 | uint8_t matrix_scan(void) | 141 | uint8_t matrix_scan(void) |
| 96 | { | 142 | { |
| 97 | 143 | ||
| 98 | #if DIODE_DIRECTION == COL2ROW | 144 | #if DIODE_DIRECTION == COL2ROW |
| 99 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | 145 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
| 100 | select_row(i); | 146 | select_row(i); |
| 101 | _delay_us(30); // without this wait read unstable value. | 147 | wait_us(30); // without this wait read unstable value. |
| 102 | matrix_row_t cols = read_cols(); | 148 | matrix_row_t cols = read_cols(); |
| 103 | if (matrix_debouncing[i] != cols) { | 149 | if (matrix_debouncing[i] != cols) { |
| 104 | matrix_debouncing[i] = cols; | 150 | matrix_debouncing[i] = cols; |
| 105 | if (debouncing) { | 151 | if (debouncing) { |
| 106 | debug("bounce!: "); debug_hex(debouncing); debug("\n"); | 152 | debug("bounce!: "); debug_hex(debouncing); debug("\n"); |
| 107 | } | 153 | } |
| 108 | debouncing = DEBOUNCE; | 154 | debouncing = DEBOUNCING_DELAY; |
| 109 | } | 155 | } |
| 110 | unselect_rows(); | 156 | unselect_rows(); |
| 111 | } | 157 | } |
| 112 | 158 | ||
| 113 | if (debouncing) { | 159 | if (debouncing) { |
| 114 | if (--debouncing) { | 160 | if (--debouncing) { |
| 115 | _delay_ms(1); | 161 | wait_ms(1); |
| 116 | } else { | 162 | } else { |
| 117 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | 163 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
| 118 | matrix[i] = matrix_debouncing[i]; | 164 | matrix[i] = matrix_debouncing[i]; |
| @@ -122,21 +168,21 @@ uint8_t matrix_scan(void) | |||
| 122 | #else | 168 | #else |
| 123 | for (uint8_t i = 0; i < MATRIX_COLS; i++) { | 169 | for (uint8_t i = 0; i < MATRIX_COLS; i++) { |
| 124 | select_row(i); | 170 | select_row(i); |
| 125 | _delay_us(30); // without this wait read unstable value. | 171 | wait_us(30); // without this wait read unstable value. |
| 126 | matrix_row_t rows = read_cols(); | 172 | matrix_row_t rows = read_cols(); |
| 127 | if (matrix_reversed_debouncing[i] != rows) { | 173 | if (matrix_reversed_debouncing[i] != rows) { |
| 128 | matrix_reversed_debouncing[i] = rows; | 174 | matrix_reversed_debouncing[i] = rows; |
| 129 | if (debouncing) { | 175 | if (debouncing) { |
| 130 | debug("bounce!: "); debug_hex(debouncing); debug("\n"); | 176 | debug("bounce!: "); debug_hex(debouncing); debug("\n"); |
| 131 | } | 177 | } |
| 132 | debouncing = DEBOUNCE; | 178 | debouncing = DEBOUNCING_DELAY; |
| 133 | } | 179 | } |
| 134 | unselect_rows(); | 180 | unselect_rows(); |
| 135 | } | 181 | } |
| 136 | 182 | ||
| 137 | if (debouncing) { | 183 | if (debouncing) { |
| 138 | if (--debouncing) { | 184 | if (--debouncing) { |
| 139 | _delay_ms(1); | 185 | wait_ms(1); |
| 140 | } else { | 186 | } else { |
| 141 | for (uint8_t i = 0; i < MATRIX_COLS; i++) { | 187 | for (uint8_t i = 0; i < MATRIX_COLS; i++) { |
| 142 | matrix_reversed[i] = matrix_reversed_debouncing[i]; | 188 | matrix_reversed[i] = matrix_reversed_debouncing[i]; |
| @@ -152,9 +198,7 @@ uint8_t matrix_scan(void) | |||
| 152 | } | 198 | } |
| 153 | #endif | 199 | #endif |
| 154 | 200 | ||
| 155 | if (matrix_scan_kb) { | 201 | matrix_scan_quantum(); |
| 156 | (*matrix_scan_kb)(); | ||
| 157 | } | ||
| 158 | 202 | ||
| 159 | return 1; | 203 | return 1; |
| 160 | } | 204 | } |
| @@ -198,32 +242,16 @@ uint8_t matrix_key_count(void) | |||
| 198 | 242 | ||
| 199 | static void init_cols(void) | 243 | static void init_cols(void) |
| 200 | { | 244 | { |
| 201 | int B = 0, C = 0, D = 0, E = 0, F = 0; | ||
| 202 | |||
| 203 | #if DIODE_DIRECTION == COL2ROW | 245 | #if DIODE_DIRECTION == COL2ROW |
| 204 | for(int x = 0; x < MATRIX_COLS; x++) { | 246 | for(int x = 0; x < MATRIX_COLS; x++) { |
| 205 | int col = COLS[x]; | 247 | int pin = col_pins[x]; |
| 206 | #else | 248 | #else |
| 207 | for(int x = 0; x < MATRIX_ROWS; x++) { | 249 | for(int x = 0; x < MATRIX_ROWS; x++) { |
| 208 | int col = ROWS[x]; | 250 | int pin = row_pins[x]; |
| 209 | #endif | 251 | #endif |
| 210 | if ((col & 0xF0) == 0x20) { | 252 | _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); |
| 211 | B |= (1<<(col & 0x0F)); | 253 | _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); |
| 212 | } else if ((col & 0xF0) == 0x30) { | ||
| 213 | C |= (1<<(col & 0x0F)); | ||
| 214 | } else if ((col & 0xF0) == 0x40) { | ||
| 215 | D |= (1<<(col & 0x0F)); | ||
| 216 | } else if ((col & 0xF0) == 0x50) { | ||
| 217 | E |= (1<<(col & 0x0F)); | ||
| 218 | } else if ((col & 0xF0) == 0x60) { | ||
| 219 | F |= (1<<(col & 0x0F)); | ||
| 220 | } | ||
| 221 | } | 254 | } |
| 222 | DDRB &= ~(B); PORTB |= (B); | ||
| 223 | DDRC &= ~(C); PORTC |= (C); | ||
| 224 | DDRD &= ~(D); PORTD |= (D); | ||
| 225 | DDRE &= ~(E); PORTE |= (E); | ||
| 226 | DDRF &= ~(F); PORTF |= (F); | ||
| 227 | } | 255 | } |
| 228 | 256 | ||
| 229 | static matrix_row_t read_cols(void) | 257 | static matrix_row_t read_cols(void) |
| @@ -232,80 +260,38 @@ static matrix_row_t read_cols(void) | |||
| 232 | 260 | ||
| 233 | #if DIODE_DIRECTION == COL2ROW | 261 | #if DIODE_DIRECTION == COL2ROW |
| 234 | for(int x = 0; x < MATRIX_COLS; x++) { | 262 | for(int x = 0; x < MATRIX_COLS; x++) { |
| 235 | int col = COLS[x]; | 263 | int pin = col_pins[x]; |
| 236 | #else | 264 | #else |
| 237 | for(int x = 0; x < MATRIX_ROWS; x++) { | 265 | for(int x = 0; x < MATRIX_ROWS; x++) { |
| 238 | int col = ROWS[x]; | 266 | int pin = row_pins[x]; |
| 239 | #endif | 267 | #endif |
| 240 | 268 | result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x); | |
| 241 | if ((col & 0xF0) == 0x20) { | ||
| 242 | result |= (PINB&(1<<(col & 0x0F)) ? 0 : (1<<x)); | ||
| 243 | } else if ((col & 0xF0) == 0x30) { | ||
| 244 | result |= (PINC&(1<<(col & 0x0F)) ? 0 : (1<<x)); | ||
| 245 | } else if ((col & 0xF0) == 0x40) { | ||
| 246 | result |= (PIND&(1<<(col & 0x0F)) ? 0 : (1<<x)); | ||
| 247 | } else if ((col & 0xF0) == 0x50) { | ||
| 248 | result |= (PINE&(1<<(col & 0x0F)) ? 0 : (1<<x)); | ||
| 249 | } else if ((col & 0xF0) == 0x60) { | ||
| 250 | result |= (PINF&(1<<(col & 0x0F)) ? 0 : (1<<x)); | ||
| 251 | } | ||
| 252 | } | 269 | } |
| 253 | return result; | 270 | return result; |
| 254 | } | 271 | } |
| 255 | 272 | ||
| 256 | static void unselect_rows(void) | 273 | static void unselect_rows(void) |
| 257 | { | 274 | { |
| 258 | int B = 0, C = 0, D = 0, E = 0, F = 0; | ||
| 259 | |||
| 260 | #if DIODE_DIRECTION == COL2ROW | 275 | #if DIODE_DIRECTION == COL2ROW |
| 261 | for(int x = 0; x < MATRIX_ROWS; x++) { | 276 | for(int x = 0; x < MATRIX_ROWS; x++) { |
| 262 | int row = ROWS[x]; | 277 | int pin = row_pins[x]; |
| 263 | #else | 278 | #else |
| 264 | for(int x = 0; x < MATRIX_COLS; x++) { | 279 | for(int x = 0; x < MATRIX_COLS; x++) { |
| 265 | int row = COLS[x]; | 280 | int pin = col_pins[x]; |
| 266 | #endif | 281 | #endif |
| 267 | if ((row & 0xF0) == 0x20) { | 282 | _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); |
| 268 | B |= (1<<(row & 0x0F)); | 283 | _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); |
| 269 | } else if ((row & 0xF0) == 0x30) { | ||
| 270 | C |= (1<<(row & 0x0F)); | ||
| 271 | } else if ((row & 0xF0) == 0x40) { | ||
| 272 | D |= (1<<(row & 0x0F)); | ||
| 273 | } else if ((row & 0xF0) == 0x50) { | ||
| 274 | E |= (1<<(row & 0x0F)); | ||
| 275 | } else if ((row & 0xF0) == 0x60) { | ||
| 276 | F |= (1<<(row & 0x0F)); | ||
| 277 | } | ||
| 278 | } | 284 | } |
| 279 | DDRB &= ~(B); PORTB |= (B); | ||
| 280 | DDRC &= ~(C); PORTC |= (C); | ||
| 281 | DDRD &= ~(D); PORTD |= (D); | ||
| 282 | DDRE &= ~(E); PORTE |= (E); | ||
| 283 | DDRF &= ~(F); PORTF |= (F); | ||
| 284 | } | 285 | } |
| 285 | 286 | ||
| 286 | static void select_row(uint8_t row) | 287 | static void select_row(uint8_t row) |
| 287 | { | 288 | { |
| 288 | 289 | ||
| 289 | #if DIODE_DIRECTION == COL2ROW | 290 | #if DIODE_DIRECTION == COL2ROW |
| 290 | int row_pin = ROWS[row]; | 291 | int pin = row_pins[row]; |
| 291 | #else | 292 | #else |
| 292 | int row_pin = COLS[row]; | 293 | int pin = col_pins[row]; |
| 293 | #endif | 294 | #endif |
| 294 | 295 | _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); | |
| 295 | if ((row_pin & 0xF0) == 0x20) { | 296 | _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); |
| 296 | DDRB |= (1<<(row_pin & 0x0F)); | 297 | } |
| 297 | PORTB &= ~(1<<(row_pin & 0x0F)); | ||
| 298 | } else if ((row_pin & 0xF0) == 0x30) { | ||
| 299 | DDRC |= (1<<(row_pin & 0x0F)); | ||
| 300 | PORTC &= ~(1<<(row_pin & 0x0F)); | ||
| 301 | } else if ((row_pin & 0xF0) == 0x40) { | ||
| 302 | DDRD |= (1<<(row_pin & 0x0F)); | ||
| 303 | PORTD &= ~(1<<(row_pin & 0x0F)); | ||
| 304 | } else if ((row_pin & 0xF0) == 0x50) { | ||
| 305 | DDRE |= (1<<(row_pin & 0x0F)); | ||
| 306 | PORTE &= ~(1<<(row_pin & 0x0F)); | ||
| 307 | } else if ((row_pin & 0xF0) == 0x60) { | ||
| 308 | DDRF |= (1<<(row_pin & 0x0F)); | ||
| 309 | PORTF &= ~(1<<(row_pin & 0x0F)); | ||
| 310 | } | ||
| 311 | } \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_chording.c b/quantum/process_keycode/process_chording.c new file mode 100644 index 000000000..d7814629f --- /dev/null +++ b/quantum/process_keycode/process_chording.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include "process_chording.h" | ||
| 2 | |||
| 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..577dad43a --- /dev/null +++ b/quantum/process_keycode/process_midi.c | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | #include "process_midi.h" | ||
| 2 | |||
| 3 | bool midi_activated = false; | ||
| 4 | uint8_t midi_starting_note = 0x0C; | ||
| 5 | int midi_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 | #ifdef AUDIO_ENABLE | ||
| 11 | music_scale_user(); | ||
| 12 | #endif | ||
| 13 | return false; | ||
| 14 | } | ||
| 15 | |||
| 16 | if (keycode == MI_OFF && record->event.pressed) { | ||
| 17 | midi_activated = false; | ||
| 18 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 19 | return false; | ||
| 20 | } | ||
| 21 | |||
| 22 | if (midi_activated) { | ||
| 23 | if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) { | ||
| 24 | if (record->event.pressed) { | ||
| 25 | midi_starting_note++; // Change key | ||
| 26 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 27 | } | ||
| 28 | return false; | ||
| 29 | } | ||
| 30 | if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) { | ||
| 31 | if (record->event.pressed) { | ||
| 32 | midi_starting_note--; // Change key | ||
| 33 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 34 | } | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { | ||
| 38 | midi_offset++; // Change scale | ||
| 39 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { | ||
| 43 | midi_offset--; // Change scale | ||
| 44 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 45 | return false; | ||
| 46 | } | ||
| 47 | // basic | ||
| 48 | // uint8_t note = (midi_starting_note + SCALE[record->event.key.col + midi_offset])+12*(MATRIX_ROWS - record->event.key.row); | ||
| 49 | // advanced | ||
| 50 | // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+12*(MATRIX_ROWS - record->event.key.row); | ||
| 51 | // guitar | ||
| 52 | uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+5*(MATRIX_ROWS - record->event.key.row); | ||
| 53 | // violin | ||
| 54 | // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+7*(MATRIX_ROWS - record->event.key.row); | ||
| 55 | |||
| 56 | if (record->event.pressed) { | ||
| 57 | // midi_send_noteon(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127); | ||
| 58 | midi_send_noteon(&midi_device, 0, note, 127); | ||
| 59 | } else { | ||
| 60 | // midi_send_noteoff(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127); | ||
| 61 | midi_send_noteoff(&midi_device, 0, note, 127); | ||
| 62 | } | ||
| 63 | |||
| 64 | if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through | ||
| 65 | return false; | ||
| 66 | } | ||
| 67 | return true; | ||
| 68 | } | ||
diff --git a/quantum/keymap_midi.h b/quantum/process_keycode/process_midi.h index a89420ce2..acd4fc1b1 100644 --- a/quantum/keymap_midi.h +++ b/quantum/process_keycode/process_midi.h | |||
| @@ -1,35 +1,20 @@ | |||
| 1 | /* | 1 | #ifndef PROCESS_MIDI_H |
| 2 | Copyright 2015 Jack Humbert <jack.humb@gmail.com> | 2 | #define PROCESS_MIDI_H |
| 3 | 3 | ||
| 4 | This program is free software: you can redistribute it and/or modify | 4 | #include "quantum.h" |
| 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 | 5 | ||
| 9 | This program is distributed in the hope that it will be useful, | 6 | bool process_midi(uint16_t keycode, keyrecord_t *record); |
| 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 | 7 | ||
| 14 | You should have received a copy of the GNU General Public License | 8 | #define MIDI(n) ((n) | 0x6000) |
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef KEYMAP_MIDI_H | ||
| 19 | #define KEYMAP_MIDI_H | ||
| 20 | |||
| 21 | #include <lufa.h> | ||
| 22 | |||
| 23 | #define MIDI 0x6000 | ||
| 24 | #define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000 | 9 | #define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000 |
| 25 | 10 | ||
| 26 | #define CHNL(note, channel) (note + (channel << 8)) | 11 | #define CHNL(note, channel) (note + (channel << 8)) |
| 27 | 12 | ||
| 28 | #define SCALE (int []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ | 13 | #define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ |
| 29 | 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ | 14 | 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ |
| 30 | 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ | 15 | 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ |
| 31 | 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ | 16 | 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ |
| 32 | 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } | 17 | 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } |
| 33 | 18 | ||
| 34 | #define N_CN1 (0x600C + (12 * -1) + 0 ) | 19 | #define N_CN1 (0x600C + (12 * -1) + 0 ) |
| 35 | #define N_CN1S (0x600C + (12 * -1) + 1 ) | 20 | #define N_CN1S (0x600C + (12 * -1) + 1 ) |
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c new file mode 100644 index 000000000..2d52e47a7 --- /dev/null +++ b/quantum/process_keycode/process_music.c | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | #include "process_music.h" | ||
| 2 | |||
| 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_recorded = false; | ||
| 10 | static bool music_sequence_playing = false; | ||
| 11 | static float music_sequence[16] = {0}; | ||
| 12 | static uint8_t music_sequence_count = 0; | ||
| 13 | static uint8_t music_sequence_position = 0; | ||
| 14 | |||
| 15 | static uint16_t music_sequence_timer = 0; | ||
| 16 | static uint16_t music_sequence_interval = 100; | ||
| 17 | |||
| 18 | bool process_music(uint16_t keycode, keyrecord_t *record) { | ||
| 19 | |||
| 20 | if (keycode == AU_ON && record->event.pressed) { | ||
| 21 | audio_on(); | ||
| 22 | return false; | ||
| 23 | } | ||
| 24 | |||
| 25 | if (keycode == AU_OFF && record->event.pressed) { | ||
| 26 | audio_off(); | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | |||
| 30 | if (keycode == AU_TOG && record->event.pressed) { | ||
| 31 | if (is_audio_on()) | ||
| 32 | { | ||
| 33 | audio_off(); | ||
| 34 | } | ||
| 35 | else | ||
| 36 | { | ||
| 37 | audio_on(); | ||
| 38 | } | ||
| 39 | return false; | ||
| 40 | } | ||
| 41 | |||
| 42 | if (keycode == MU_ON && record->event.pressed) { | ||
| 43 | music_on(); | ||
| 44 | return false; | ||
| 45 | } | ||
| 46 | |||
| 47 | if (keycode == MU_OFF && record->event.pressed) { | ||
| 48 | music_off(); | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | |||
| 52 | if (keycode == MU_TOG && record->event.pressed) { | ||
| 53 | if (music_activated) | ||
| 54 | { | ||
| 55 | music_off(); | ||
| 56 | } | ||
| 57 | else | ||
| 58 | { | ||
| 59 | music_on(); | ||
| 60 | } | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | |||
| 64 | if (keycode == MUV_IN && record->event.pressed) { | ||
| 65 | voice_iterate(); | ||
| 66 | music_scale_user(); | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (keycode == MUV_DE && record->event.pressed) { | ||
| 71 | voice_deiterate(); | ||
| 72 | music_scale_user(); | ||
| 73 | return false; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (music_activated) { | ||
| 77 | |||
| 78 | if (keycode == KC_LCTL && record->event.pressed) { // Start recording | ||
| 79 | stop_all_notes(); | ||
| 80 | music_sequence_recording = true; | ||
| 81 | music_sequence_recorded = false; | ||
| 82 | music_sequence_playing = false; | ||
| 83 | music_sequence_count = 0; | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing | ||
| 88 | stop_all_notes(); | ||
| 89 | if (music_sequence_recording) { // was recording | ||
| 90 | music_sequence_recorded = true; | ||
| 91 | } | ||
| 92 | music_sequence_recording = false; | ||
| 93 | music_sequence_playing = false; | ||
| 94 | return false; | ||
| 95 | } | ||
| 96 | |||
| 97 | if (keycode == KC_LGUI && record->event.pressed && music_sequence_recorded) { // Start playing | ||
| 98 | stop_all_notes(); | ||
| 99 | music_sequence_recording = false; | ||
| 100 | music_sequence_playing = true; | ||
| 101 | music_sequence_position = 0; | ||
| 102 | music_sequence_timer = 0; | ||
| 103 | return false; | ||
| 104 | } | ||
| 105 | |||
| 106 | if (keycode == KC_UP) { | ||
| 107 | if (record->event.pressed) | ||
| 108 | music_sequence_interval-=10; | ||
| 109 | return false; | ||
| 110 | } | ||
| 111 | |||
| 112 | if (keycode == KC_DOWN) { | ||
| 113 | if (record->event.pressed) | ||
| 114 | music_sequence_interval+=10; | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | |||
| 118 | float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)); | ||
| 119 | if (record->event.pressed) { | ||
| 120 | play_note(freq, 0xF); | ||
| 121 | if (music_sequence_recording) { | ||
| 122 | music_sequence[music_sequence_count] = freq; | ||
| 123 | music_sequence_count++; | ||
| 124 | } | ||
| 125 | } else { | ||
| 126 | stop_note(freq); | ||
| 127 | } | ||
| 128 | |||
| 129 | if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through | ||
| 130 | return false; | ||
| 131 | } | ||
| 132 | return true; | ||
| 133 | } | ||
| 134 | |||
| 135 | bool is_music_on(void) { | ||
| 136 | return (music_activated != 0); | ||
| 137 | } | ||
| 138 | |||
| 139 | void music_toggle(void) { | ||
| 140 | if (!music_activated) { | ||
| 141 | music_on(); | ||
| 142 | } else { | ||
| 143 | music_off(); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | void music_on(void) { | ||
| 148 | music_activated = 1; | ||
| 149 | music_on_user(); | ||
| 150 | } | ||
| 151 | |||
| 152 | void music_off(void) { | ||
| 153 | music_activated = 0; | ||
| 154 | stop_all_notes(); | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | __attribute__ ((weak)) | ||
| 159 | void music_on_user() {} | ||
| 160 | |||
| 161 | __attribute__ ((weak)) | ||
| 162 | void audio_on_user() {} | ||
| 163 | |||
| 164 | __attribute__ ((weak)) | ||
| 165 | void music_scale_user() {} | ||
| 166 | |||
| 167 | void matrix_scan_music(void) { | ||
| 168 | if (music_sequence_playing) { | ||
| 169 | if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) { | ||
| 170 | music_sequence_timer = timer_read(); | ||
| 171 | stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]); | ||
| 172 | play_note(music_sequence[music_sequence_position], 0xF); | ||
| 173 | music_sequence_position = (music_sequence_position + 1) % music_sequence_count; | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h new file mode 100644 index 000000000..318b3e387 --- /dev/null +++ b/quantum/process_keycode/process_music.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #ifndef PROCESS_MUSIC_H | ||
| 2 | #define PROCESS_MUSIC_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 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..6ae362c4c --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.c | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | #include "quantum.h" | ||
| 2 | #include "action_tapping.h" | ||
| 3 | |||
| 4 | static uint16_t last_td; | ||
| 5 | static int8_t highest_td = -1; | ||
| 6 | |||
| 7 | void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data) { | ||
| 8 | qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; | ||
| 9 | |||
| 10 | if (state->count == 1) { | ||
| 11 | register_code16 (pair->kc1); | ||
| 12 | } else if (state->count == 2) { | ||
| 13 | register_code16 (pair->kc2); | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) { | ||
| 18 | qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; | ||
| 19 | |||
| 20 | if (state->count == 1) { | ||
| 21 | unregister_code16 (pair->kc1); | ||
| 22 | } else if (state->count == 2) { | ||
| 23 | unregister_code16 (pair->kc2); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, | ||
| 28 | void *user_data, | ||
| 29 | qk_tap_dance_user_fn_t fn) | ||
| 30 | { | ||
| 31 | if (fn) { | ||
| 32 | fn(state, user_data); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t *action) | ||
| 37 | { | ||
| 38 | _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_each_tap); | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t *action) | ||
| 42 | { | ||
| 43 | if (action->state.finished) | ||
| 44 | return; | ||
| 45 | action->state.finished = true; | ||
| 46 | _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action) | ||
| 50 | { | ||
| 51 | _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset); | ||
| 52 | } | ||
| 53 | |||
| 54 | bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { | ||
| 55 | uint16_t idx = keycode - QK_TAP_DANCE; | ||
| 56 | qk_tap_dance_action_t *action; | ||
| 57 | |||
| 58 | if (last_td && last_td != keycode) { | ||
| 59 | (&tap_dance_actions[last_td - QK_TAP_DANCE])->state.interrupted = true; | ||
| 60 | } | ||
| 61 | |||
| 62 | switch(keycode) { | ||
| 63 | case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: | ||
| 64 | if ((int16_t)idx > highest_td) | ||
| 65 | highest_td = idx; | ||
| 66 | action = &tap_dance_actions[idx]; | ||
| 67 | |||
| 68 | action->state.pressed = record->event.pressed; | ||
| 69 | if (record->event.pressed) { | ||
| 70 | action->state.keycode = keycode; | ||
| 71 | action->state.count++; | ||
| 72 | action->state.timer = timer_read(); | ||
| 73 | process_tap_dance_action_on_each_tap (action); | ||
| 74 | |||
| 75 | if (last_td && last_td != keycode) { | ||
| 76 | qk_tap_dance_action_t *paction = &tap_dance_actions[last_td - QK_TAP_DANCE]; | ||
| 77 | paction->state.interrupted = true; | ||
| 78 | process_tap_dance_action_on_dance_finished (paction); | ||
| 79 | reset_tap_dance (&paction->state); | ||
| 80 | } | ||
| 81 | |||
| 82 | last_td = keycode; | ||
| 83 | } | ||
| 84 | |||
| 85 | break; | ||
| 86 | |||
| 87 | default: | ||
| 88 | if (!record->event.pressed) | ||
| 89 | return true; | ||
| 90 | |||
| 91 | if (highest_td == -1) | ||
| 92 | return true; | ||
| 93 | |||
| 94 | for (int i = 0; i <= highest_td; i++) { | ||
| 95 | action = &tap_dance_actions[i]; | ||
| 96 | if (action->state.count == 0) | ||
| 97 | continue; | ||
| 98 | action->state.interrupted = true; | ||
| 99 | process_tap_dance_action_on_dance_finished (action); | ||
| 100 | reset_tap_dance (&action->state); | ||
| 101 | } | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | |||
| 105 | return true; | ||
| 106 | } | ||
| 107 | |||
| 108 | void matrix_scan_tap_dance () { | ||
| 109 | if (highest_td == -1) | ||
| 110 | return; | ||
| 111 | |||
| 112 | for (int i = 0; i <= highest_td; i++) { | ||
| 113 | qk_tap_dance_action_t *action = &tap_dance_actions[i]; | ||
| 114 | |||
| 115 | if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) { | ||
| 116 | process_tap_dance_action_on_dance_finished (action); | ||
| 117 | reset_tap_dance (&action->state); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | void reset_tap_dance (qk_tap_dance_state_t *state) { | ||
| 123 | qk_tap_dance_action_t *action; | ||
| 124 | |||
| 125 | if (state->pressed) | ||
| 126 | return; | ||
| 127 | |||
| 128 | action = &tap_dance_actions[state->keycode - QK_TAP_DANCE]; | ||
| 129 | |||
| 130 | process_tap_dance_action_on_reset (action); | ||
| 131 | |||
| 132 | state->count = 0; | ||
| 133 | state->interrupted = false; | ||
| 134 | state->finished = false; | ||
| 135 | last_td = 0; | ||
| 136 | } | ||
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h new file mode 100644 index 000000000..f753cbba6 --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.h | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | #ifndef PROCESS_TAP_DANCE_H | ||
| 2 | #define PROCESS_TAP_DANCE_H | ||
| 3 | |||
| 4 | #ifdef TAP_DANCE_ENABLE | ||
| 5 | |||
| 6 | #include <stdbool.h> | ||
| 7 | #include <inttypes.h> | ||
| 8 | |||
| 9 | typedef struct | ||
| 10 | { | ||
| 11 | uint8_t count; | ||
| 12 | uint16_t keycode; | ||
| 13 | uint16_t timer; | ||
| 14 | bool interrupted; | ||
| 15 | bool pressed; | ||
| 16 | bool finished; | ||
| 17 | } qk_tap_dance_state_t; | ||
| 18 | |||
| 19 | #define TD(n) (QK_TAP_DANCE + n) | ||
| 20 | |||
| 21 | typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state, void *user_data); | ||
| 22 | |||
| 23 | typedef struct | ||
| 24 | { | ||
| 25 | struct { | ||
| 26 | qk_tap_dance_user_fn_t on_each_tap; | ||
| 27 | qk_tap_dance_user_fn_t on_dance_finished; | ||
| 28 | qk_tap_dance_user_fn_t on_reset; | ||
| 29 | } fn; | ||
| 30 | qk_tap_dance_state_t state; | ||
| 31 | void *user_data; | ||
| 32 | } qk_tap_dance_action_t; | ||
| 33 | |||
| 34 | typedef struct | ||
| 35 | { | ||
| 36 | uint16_t kc1; | ||
| 37 | uint16_t kc2; | ||
| 38 | } qk_tap_dance_pair_t; | ||
| 39 | |||
| 40 | #define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \ | ||
| 41 | .fn = { NULL, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset }, \ | ||
| 42 | .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }), \ | ||
| 43 | } | ||
| 44 | |||
| 45 | #define ACTION_TAP_DANCE_FN(user_fn) { \ | ||
| 46 | .fn = { NULL, user_fn, NULL }, \ | ||
| 47 | .user_data = NULL, \ | ||
| 48 | } | ||
| 49 | |||
| 50 | #define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset) { \ | ||
| 51 | .fn = { user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset }, \ | ||
| 52 | .user_data = NULL, \ | ||
| 53 | } | ||
| 54 | |||
| 55 | extern qk_tap_dance_action_t tap_dance_actions[]; | ||
| 56 | |||
| 57 | /* To be used internally */ | ||
| 58 | |||
| 59 | bool process_tap_dance(uint16_t keycode, keyrecord_t *record); | ||
| 60 | void matrix_scan_tap_dance (void); | ||
| 61 | void reset_tap_dance (qk_tap_dance_state_t *state); | ||
| 62 | |||
| 63 | void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data); | ||
| 64 | void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data); | ||
| 65 | |||
| 66 | #else | ||
| 67 | |||
| 68 | #define TD(n) KC_NO | ||
| 69 | |||
| 70 | #endif | ||
| 71 | |||
| 72 | #endif | ||
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c new file mode 100644 index 000000000..cd3a610b4 --- /dev/null +++ b/quantum/process_keycode/process_unicode.c | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | #include "process_unicode.h" | ||
| 2 | |||
| 3 | static uint8_t input_mode; | ||
| 4 | |||
| 5 | __attribute__((weak)) | ||
| 6 | uint16_t hex_to_keycode(uint8_t hex) | ||
| 7 | { | ||
| 8 | if (hex == 0x0) { | ||
| 9 | return KC_0; | ||
| 10 | } else if (hex < 0xA) { | ||
| 11 | return KC_1 + (hex - 0x1); | ||
| 12 | } else { | ||
| 13 | return KC_A + (hex - 0xA); | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | void set_unicode_input_mode(uint8_t os_target) | ||
| 18 | { | ||
| 19 | input_mode = os_target; | ||
| 20 | } | ||
| 21 | |||
| 22 | uint8_t get_unicode_input_mode(void) { | ||
| 23 | return input_mode; | ||
| 24 | } | ||
| 25 | |||
| 26 | __attribute__((weak)) | ||
| 27 | void unicode_input_start (void) { | ||
| 28 | switch(input_mode) { | ||
| 29 | case UC_OSX: | ||
| 30 | register_code(KC_LALT); | ||
| 31 | break; | ||
| 32 | case UC_LNX: | ||
| 33 | register_code(KC_LCTL); | ||
| 34 | register_code(KC_LSFT); | ||
| 35 | register_code(KC_U); | ||
| 36 | unregister_code(KC_U); | ||
| 37 | unregister_code(KC_LSFT); | ||
| 38 | unregister_code(KC_LCTL); | ||
| 39 | break; | ||
| 40 | case UC_WIN: | ||
| 41 | register_code(KC_LALT); | ||
| 42 | register_code(KC_PPLS); | ||
| 43 | unregister_code(KC_PPLS); | ||
| 44 | break; | ||
| 45 | case UC_WINC: | ||
| 46 | register_code(KC_RALT); | ||
| 47 | unregister_code(KC_RALT); | ||
| 48 | register_code(KC_U); | ||
| 49 | unregister_code(KC_U); | ||
| 50 | } | ||
| 51 | wait_ms(UNICODE_TYPE_DELAY); | ||
| 52 | } | ||
| 53 | |||
| 54 | __attribute__((weak)) | ||
| 55 | void unicode_input_finish (void) { | ||
| 56 | switch(input_mode) { | ||
| 57 | case UC_OSX: | ||
| 58 | case UC_WIN: | ||
| 59 | unregister_code(KC_LALT); | ||
| 60 | break; | ||
| 61 | case UC_LNX: | ||
| 62 | register_code(KC_SPC); | ||
| 63 | unregister_code(KC_SPC); | ||
| 64 | break; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | void register_hex(uint16_t hex) { | ||
| 69 | for(int i = 3; i >= 0; i--) { | ||
| 70 | uint8_t digit = ((hex >> (i*4)) & 0xF); | ||
| 71 | register_code(hex_to_keycode(digit)); | ||
| 72 | unregister_code(hex_to_keycode(digit)); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | bool process_unicode(uint16_t keycode, keyrecord_t *record) { | ||
| 77 | if (keycode > QK_UNICODE && record->event.pressed) { | ||
| 78 | uint16_t unicode = keycode & 0x7FFF; | ||
| 79 | unicode_input_start(); | ||
| 80 | register_hex(unicode); | ||
| 81 | unicode_input_finish(); | ||
| 82 | } | ||
| 83 | return true; | ||
| 84 | } | ||
| 85 | |||
| 86 | #ifdef UNICODEMAP_ENABLE | ||
| 87 | __attribute__((weak)) | ||
| 88 | const uint32_t PROGMEM unicode_map[] = { | ||
| 89 | }; | ||
| 90 | |||
| 91 | void register_hex32(uint32_t hex) { | ||
| 92 | uint8_t onzerostart = 1; | ||
| 93 | for(int i = 7; i >= 0; i--) { | ||
| 94 | if (i <= 3) { | ||
| 95 | onzerostart = 0; | ||
| 96 | } | ||
| 97 | uint8_t digit = ((hex >> (i*4)) & 0xF); | ||
| 98 | if (digit == 0) { | ||
| 99 | if (onzerostart == 0) { | ||
| 100 | register_code(hex_to_keycode(digit)); | ||
| 101 | unregister_code(hex_to_keycode(digit)); | ||
| 102 | } | ||
| 103 | } else { | ||
| 104 | register_code(hex_to_keycode(digit)); | ||
| 105 | unregister_code(hex_to_keycode(digit)); | ||
| 106 | onzerostart = 0; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | __attribute__((weak)) | ||
| 112 | void unicode_map_input_error() {} | ||
| 113 | |||
| 114 | bool process_unicode_map(uint16_t keycode, keyrecord_t *record) { | ||
| 115 | if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) { | ||
| 116 | const uint32_t* map = unicode_map; | ||
| 117 | uint16_t index = keycode & 0x7FF; | ||
| 118 | uint32_t code = pgm_read_dword_far(&map[index]); | ||
| 119 | if ((code > 0xFFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) { | ||
| 120 | // when character is out of range supported by the OS | ||
| 121 | unicode_map_input_error(); | ||
| 122 | } else { | ||
| 123 | unicode_input_start(); | ||
| 124 | register_hex32(code); | ||
| 125 | unicode_input_finish(); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | return true; | ||
| 129 | } | ||
| 130 | #endif | ||
| 131 | |||
| 132 | #ifdef UCIS_ENABLE | ||
| 133 | qk_ucis_state_t qk_ucis_state; | ||
| 134 | |||
| 135 | void qk_ucis_start(void) { | ||
| 136 | qk_ucis_state.count = 0; | ||
| 137 | qk_ucis_state.in_progress = true; | ||
| 138 | |||
| 139 | qk_ucis_start_user(); | ||
| 140 | } | ||
| 141 | |||
| 142 | __attribute__((weak)) | ||
| 143 | void qk_ucis_start_user(void) { | ||
| 144 | unicode_input_start(); | ||
| 145 | register_hex(0x2328); | ||
| 146 | unicode_input_finish(); | ||
| 147 | } | ||
| 148 | |||
| 149 | static bool is_uni_seq(char *seq) { | ||
| 150 | uint8_t i; | ||
| 151 | |||
| 152 | for (i = 0; seq[i]; i++) { | ||
| 153 | uint16_t code; | ||
| 154 | if (('1' <= seq[i]) && (seq[i] <= '0')) | ||
| 155 | code = seq[i] - '1' + KC_1; | ||
| 156 | else | ||
| 157 | code = seq[i] - 'a' + KC_A; | ||
| 158 | |||
| 159 | if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code) | ||
| 160 | return false; | ||
| 161 | } | ||
| 162 | |||
| 163 | return (qk_ucis_state.codes[i] == KC_ENT || | ||
| 164 | qk_ucis_state.codes[i] == KC_SPC); | ||
| 165 | } | ||
| 166 | |||
| 167 | __attribute__((weak)) | ||
| 168 | void qk_ucis_symbol_fallback (void) { | ||
| 169 | for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { | ||
| 170 | uint8_t code = qk_ucis_state.codes[i]; | ||
| 171 | register_code(code); | ||
| 172 | unregister_code(code); | ||
| 173 | wait_ms(UNICODE_TYPE_DELAY); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | void register_ucis(const char *hex) { | ||
| 178 | for(int i = 0; hex[i]; i++) { | ||
| 179 | uint8_t kc = 0; | ||
| 180 | char c = hex[i]; | ||
| 181 | |||
| 182 | switch (c) { | ||
| 183 | case '0': | ||
| 184 | kc = KC_0; | ||
| 185 | break; | ||
| 186 | case '1' ... '9': | ||
| 187 | kc = c - '1' + KC_1; | ||
| 188 | break; | ||
| 189 | case 'a' ... 'f': | ||
| 190 | kc = c - 'a' + KC_A; | ||
| 191 | break; | ||
| 192 | case 'A' ... 'F': | ||
| 193 | kc = c - 'A' + KC_A; | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (kc) { | ||
| 198 | register_code (kc); | ||
| 199 | unregister_code (kc); | ||
| 200 | wait_ms (UNICODE_TYPE_DELAY); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | bool process_ucis (uint16_t keycode, keyrecord_t *record) { | ||
| 206 | uint8_t i; | ||
| 207 | |||
| 208 | if (!qk_ucis_state.in_progress) | ||
| 209 | return true; | ||
| 210 | |||
| 211 | if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH && | ||
| 212 | !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) { | ||
| 213 | return false; | ||
| 214 | } | ||
| 215 | |||
| 216 | if (!record->event.pressed) | ||
| 217 | return true; | ||
| 218 | |||
| 219 | qk_ucis_state.codes[qk_ucis_state.count] = keycode; | ||
| 220 | qk_ucis_state.count++; | ||
| 221 | |||
| 222 | if (keycode == KC_BSPC) { | ||
| 223 | if (qk_ucis_state.count >= 2) { | ||
| 224 | qk_ucis_state.count -= 2; | ||
| 225 | return true; | ||
| 226 | } else { | ||
| 227 | qk_ucis_state.count--; | ||
| 228 | return false; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) { | ||
| 233 | bool symbol_found = false; | ||
| 234 | |||
| 235 | for (i = qk_ucis_state.count; i > 0; i--) { | ||
| 236 | register_code (KC_BSPC); | ||
| 237 | unregister_code (KC_BSPC); | ||
| 238 | wait_ms(UNICODE_TYPE_DELAY); | ||
| 239 | } | ||
| 240 | |||
| 241 | if (keycode == KC_ESC) { | ||
| 242 | qk_ucis_state.in_progress = false; | ||
| 243 | return false; | ||
| 244 | } | ||
| 245 | |||
| 246 | unicode_input_start(); | ||
| 247 | for (i = 0; ucis_symbol_table[i].symbol; i++) { | ||
| 248 | if (is_uni_seq (ucis_symbol_table[i].symbol)) { | ||
| 249 | symbol_found = true; | ||
| 250 | register_ucis(ucis_symbol_table[i].code + 2); | ||
| 251 | break; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | if (!symbol_found) { | ||
| 255 | qk_ucis_symbol_fallback(); | ||
| 256 | } | ||
| 257 | unicode_input_finish(); | ||
| 258 | |||
| 259 | qk_ucis_state.in_progress = false; | ||
| 260 | return false; | ||
| 261 | } | ||
| 262 | return true; | ||
| 263 | } | ||
| 264 | #endif | ||
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h new file mode 100644 index 000000000..065eeb5f6 --- /dev/null +++ b/quantum/process_keycode/process_unicode.h | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | #ifndef PROCESS_UNICODE_H | ||
| 2 | #define PROCESS_UNICODE_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | #define UC_OSX 0 // Mac OS X | ||
| 7 | #define UC_LNX 1 // Linux | ||
| 8 | #define UC_WIN 2 // Windows 'HexNumpad' | ||
| 9 | #define UC_BSD 3 // BSD (not implemented) | ||
| 10 | #define UC_WINC 4 // WinCompose https://github.com/samhocevar/wincompose | ||
| 11 | |||
| 12 | #ifndef UNICODE_TYPE_DELAY | ||
| 13 | #define UNICODE_TYPE_DELAY 10 | ||
| 14 | #endif | ||
| 15 | |||
| 16 | void set_unicode_input_mode(uint8_t os_target); | ||
| 17 | uint8_t get_unicode_input_mode(void); | ||
| 18 | void unicode_input_start(void); | ||
| 19 | void unicode_input_finish(void); | ||
| 20 | void register_hex(uint16_t hex); | ||
| 21 | |||
| 22 | bool process_unicode(uint16_t keycode, keyrecord_t *record); | ||
| 23 | |||
| 24 | #ifdef UNICODEMAP_ENABLE | ||
| 25 | bool process_unicode_map(uint16_t keycode, keyrecord_t *record); | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #ifdef UCIS_ENABLE | ||
| 29 | #ifndef UCIS_MAX_SYMBOL_LENGTH | ||
| 30 | #define UCIS_MAX_SYMBOL_LENGTH 32 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | typedef struct { | ||
| 34 | char *symbol; | ||
| 35 | char *code; | ||
| 36 | } qk_ucis_symbol_t; | ||
| 37 | |||
| 38 | typedef struct { | ||
| 39 | uint8_t count; | ||
| 40 | uint16_t codes[UCIS_MAX_SYMBOL_LENGTH]; | ||
| 41 | bool in_progress:1; | ||
| 42 | } qk_ucis_state_t; | ||
| 43 | |||
| 44 | extern qk_ucis_state_t qk_ucis_state; | ||
| 45 | |||
| 46 | #define UCIS_TABLE(...) {__VA_ARGS__, {NULL, NULL}} | ||
| 47 | #define UCIS_SYM(name, code) {name, #code} | ||
| 48 | |||
| 49 | extern const qk_ucis_symbol_t ucis_symbol_table[]; | ||
| 50 | |||
| 51 | void qk_ucis_start(void); | ||
| 52 | void qk_ucis_start_user(void); | ||
| 53 | void qk_ucis_symbol_fallback (void); | ||
| 54 | void register_ucis(const char *hex); | ||
| 55 | bool process_ucis (uint16_t keycode, keyrecord_t *record); | ||
| 56 | |||
| 57 | #endif | ||
| 58 | |||
| 59 | #define UC_BSPC UC(0x0008) | ||
| 60 | |||
| 61 | #define UC_SPC UC(0x0020) | ||
| 62 | |||
| 63 | #define UC_EXLM UC(0x0021) | ||
| 64 | #define UC_DQUT UC(0x0022) | ||
| 65 | #define UC_HASH UC(0x0023) | ||
| 66 | #define UC_DLR UC(0x0024) | ||
| 67 | #define UC_PERC UC(0x0025) | ||
| 68 | #define UC_AMPR UC(0x0026) | ||
| 69 | #define UC_QUOT UC(0x0027) | ||
| 70 | #define UC_LPRN UC(0x0028) | ||
| 71 | #define UC_RPRN UC(0x0029) | ||
| 72 | #define UC_ASTR UC(0x002A) | ||
| 73 | #define UC_PLUS UC(0x002B) | ||
| 74 | #define UC_COMM UC(0x002C) | ||
| 75 | #define UC_DASH UC(0x002D) | ||
| 76 | #define UC_DOT UC(0x002E) | ||
| 77 | #define UC_SLSH UC(0x002F) | ||
| 78 | |||
| 79 | #define UC_0 UC(0x0030) | ||
| 80 | #define UC_1 UC(0x0031) | ||
| 81 | #define UC_2 UC(0x0032) | ||
| 82 | #define UC_3 UC(0x0033) | ||
| 83 | #define UC_4 UC(0x0034) | ||
| 84 | #define UC_5 UC(0x0035) | ||
| 85 | #define UC_6 UC(0x0036) | ||
| 86 | #define UC_7 UC(0x0037) | ||
| 87 | #define UC_8 UC(0x0038) | ||
| 88 | #define UC_9 UC(0x0039) | ||
| 89 | |||
| 90 | #define UC_COLN UC(0x003A) | ||
| 91 | #define UC_SCLN UC(0x003B) | ||
| 92 | #define UC_LT UC(0x003C) | ||
| 93 | #define UC_EQL UC(0x003D) | ||
| 94 | #define UC_GT UC(0x003E) | ||
| 95 | #define UC_QUES UC(0x003F) | ||
| 96 | #define UC_AT UC(0x0040) | ||
| 97 | |||
| 98 | #define UC_A UC(0x0041) | ||
| 99 | #define UC_B UC(0x0042) | ||
| 100 | #define UC_C UC(0x0043) | ||
| 101 | #define UC_D UC(0x0044) | ||
| 102 | #define UC_E UC(0x0045) | ||
| 103 | #define UC_F UC(0x0046) | ||
| 104 | #define UC_G UC(0x0047) | ||
| 105 | #define UC_H UC(0x0048) | ||
| 106 | #define UC_I UC(0x0049) | ||
| 107 | #define UC_J UC(0x004A) | ||
| 108 | #define UC_K UC(0x004B) | ||
| 109 | #define UC_L UC(0x004C) | ||
| 110 | #define UC_M UC(0x004D) | ||
| 111 | #define UC_N UC(0x004E) | ||
| 112 | #define UC_O UC(0x004F) | ||
| 113 | #define UC_P UC(0x0050) | ||
| 114 | #define UC_Q UC(0x0051) | ||
| 115 | #define UC_R UC(0x0052) | ||
| 116 | #define UC_S UC(0x0053) | ||
| 117 | #define UC_T UC(0x0054) | ||
| 118 | #define UC_U UC(0x0055) | ||
| 119 | #define UC_V UC(0x0056) | ||
| 120 | #define UC_W UC(0x0057) | ||
| 121 | #define UC_X UC(0x0058) | ||
| 122 | #define UC_Y UC(0x0059) | ||
| 123 | #define UC_Z UC(0x005A) | ||
| 124 | |||
| 125 | #define UC_LBRC UC(0x005B) | ||
| 126 | #define UC_BSLS UC(0x005C) | ||
| 127 | #define UC_RBRC UC(0x005D) | ||
| 128 | #define UC_CIRM UC(0x005E) | ||
| 129 | #define UC_UNDR UC(0x005F) | ||
| 130 | |||
| 131 | #define UC_GRV UC(0x0060) | ||
| 132 | |||
| 133 | #define UC_a UC(0x0061) | ||
| 134 | #define UC_b UC(0x0062) | ||
| 135 | #define UC_c UC(0x0063) | ||
| 136 | #define UC_d UC(0x0064) | ||
| 137 | #define UC_e UC(0x0065) | ||
| 138 | #define UC_f UC(0x0066) | ||
| 139 | #define UC_g UC(0x0067) | ||
| 140 | #define UC_h UC(0x0068) | ||
| 141 | #define UC_i UC(0x0069) | ||
| 142 | #define UC_j UC(0x006A) | ||
| 143 | #define UC_k UC(0x006B) | ||
| 144 | #define UC_l UC(0x006C) | ||
| 145 | #define UC_m UC(0x006D) | ||
| 146 | #define UC_n UC(0x006E) | ||
| 147 | #define UC_o UC(0x006F) | ||
| 148 | #define UC_p UC(0x0070) | ||
| 149 | #define UC_q UC(0x0071) | ||
| 150 | #define UC_r UC(0x0072) | ||
| 151 | #define UC_s UC(0x0073) | ||
| 152 | #define UC_t UC(0x0074) | ||
| 153 | #define UC_u UC(0x0075) | ||
| 154 | #define UC_v UC(0x0076) | ||
| 155 | #define UC_w UC(0x0077) | ||
| 156 | #define UC_x UC(0x0078) | ||
| 157 | #define UC_y UC(0x0079) | ||
| 158 | #define UC_z UC(0x007A) | ||
| 159 | |||
| 160 | #define UC_LCBR UC(0x007B) | ||
| 161 | #define UC_PIPE UC(0x007C) | ||
| 162 | #define UC_RCBR UC(0x007D) | ||
| 163 | #define UC_TILD UC(0x007E) | ||
| 164 | #define UC_DEL UC(0x007F) | ||
| 165 | |||
| 166 | #endif | ||
diff --git a/quantum/quantum.c b/quantum/quantum.c new file mode 100644 index 000000000..098312e6e --- /dev/null +++ b/quantum/quantum.c | |||
| @@ -0,0 +1,853 @@ | |||
| 1 | #include "quantum.h" | ||
| 2 | |||
| 3 | static void do_code16 (uint16_t code, void (*f) (uint8_t)) { | ||
| 4 | switch (code) { | ||
| 5 | case QK_MODS ... QK_MODS_MAX: | ||
| 6 | break; | ||
| 7 | default: | ||
| 8 | return; | ||
| 9 | } | ||
| 10 | |||
| 11 | if (code & QK_LCTL) | ||
| 12 | f(KC_LCTL); | ||
| 13 | if (code & QK_LSFT) | ||
| 14 | f(KC_LSFT); | ||
| 15 | if (code & QK_LALT) | ||
| 16 | f(KC_LALT); | ||
| 17 | if (code & QK_LGUI) | ||
| 18 | f(KC_LGUI); | ||
| 19 | |||
| 20 | if (code & QK_RCTL) | ||
| 21 | f(KC_RCTL); | ||
| 22 | if (code & QK_RSFT) | ||
| 23 | f(KC_RSFT); | ||
| 24 | if (code & QK_RALT) | ||
| 25 | f(KC_RALT); | ||
| 26 | if (code & QK_RGUI) | ||
| 27 | f(KC_RGUI); | ||
| 28 | } | ||
| 29 | |||
| 30 | void register_code16 (uint16_t code) { | ||
| 31 | do_code16 (code, register_code); | ||
| 32 | register_code (code); | ||
| 33 | } | ||
| 34 | |||
| 35 | void unregister_code16 (uint16_t code) { | ||
| 36 | unregister_code (code); | ||
| 37 | do_code16 (code, unregister_code); | ||
| 38 | } | ||
| 39 | |||
| 40 | __attribute__ ((weak)) | ||
| 41 | bool process_action_kb(keyrecord_t *record) { | ||
| 42 | return true; | ||
| 43 | } | ||
| 44 | |||
| 45 | __attribute__ ((weak)) | ||
| 46 | bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | ||
| 47 | return process_record_user(keycode, record); | ||
| 48 | } | ||
| 49 | |||
| 50 | __attribute__ ((weak)) | ||
| 51 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
| 52 | return true; | ||
| 53 | } | ||
| 54 | |||
| 55 | void reset_keyboard(void) { | ||
| 56 | clear_keyboard(); | ||
| 57 | #ifdef AUDIO_ENABLE | ||
| 58 | stop_all_notes(); | ||
| 59 | shutdown_user(); | ||
| 60 | #endif | ||
| 61 | wait_ms(250); | ||
| 62 | #ifdef CATERINA_BOOTLOADER | ||
| 63 | *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific | ||
| 64 | #endif | ||
| 65 | bootloader_jump(); | ||
| 66 | } | ||
| 67 | |||
| 68 | // Shift / paren setup | ||
| 69 | |||
| 70 | #ifndef LSPO_KEY | ||
| 71 | #define LSPO_KEY KC_9 | ||
| 72 | #endif | ||
| 73 | #ifndef RSPC_KEY | ||
| 74 | #define RSPC_KEY KC_0 | ||
| 75 | #endif | ||
| 76 | |||
| 77 | static bool shift_interrupted[2] = {0, 0}; | ||
| 78 | |||
| 79 | bool process_record_quantum(keyrecord_t *record) { | ||
| 80 | |||
| 81 | /* This gets the keycode from the key pressed */ | ||
| 82 | keypos_t key = record->event.key; | ||
| 83 | uint16_t keycode; | ||
| 84 | |||
| 85 | #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) | ||
| 86 | /* TODO: Use store_or_get_action() or a similar function. */ | ||
| 87 | if (!disable_action_cache) { | ||
| 88 | uint8_t layer; | ||
| 89 | |||
| 90 | if (record->event.pressed) { | ||
| 91 | layer = layer_switch_get_layer(key); | ||
| 92 | update_source_layers_cache(key, layer); | ||
| 93 | } else { | ||
| 94 | layer = read_source_layers_cache(key); | ||
| 95 | } | ||
| 96 | keycode = keymap_key_to_keycode(layer, key); | ||
| 97 | } else | ||
| 98 | #endif | ||
| 99 | keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key); | ||
| 100 | |||
| 101 | // This is how you use actions here | ||
| 102 | // if (keycode == KC_LEAD) { | ||
| 103 | // action_t action; | ||
| 104 | // action.code = ACTION_DEFAULT_LAYER_SET(0); | ||
| 105 | // process_action(record, action); | ||
| 106 | // return false; | ||
| 107 | // } | ||
| 108 | |||
| 109 | if (!( | ||
| 110 | process_record_kb(keycode, record) && | ||
| 111 | #ifdef MIDI_ENABLE | ||
| 112 | process_midi(keycode, record) && | ||
| 113 | #endif | ||
| 114 | #ifdef AUDIO_ENABLE | ||
| 115 | process_music(keycode, record) && | ||
| 116 | #endif | ||
| 117 | #ifdef TAP_DANCE_ENABLE | ||
| 118 | process_tap_dance(keycode, record) && | ||
| 119 | #endif | ||
| 120 | #ifndef DISABLE_LEADER | ||
| 121 | process_leader(keycode, record) && | ||
| 122 | #endif | ||
| 123 | #ifndef DISABLE_CHORDING | ||
| 124 | process_chording(keycode, record) && | ||
| 125 | #endif | ||
| 126 | #ifdef UNICODE_ENABLE | ||
| 127 | process_unicode(keycode, record) && | ||
| 128 | #endif | ||
| 129 | #ifdef UCIS_ENABLE | ||
| 130 | process_ucis(keycode, record) && | ||
| 131 | #endif | ||
| 132 | #ifdef UNICODEMAP_ENABLE | ||
| 133 | process_unicode_map(keycode, record) && | ||
| 134 | #endif | ||
| 135 | true)) { | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | |||
| 139 | // Shift / paren setup | ||
| 140 | |||
| 141 | switch(keycode) { | ||
| 142 | case RESET: | ||
| 143 | if (record->event.pressed) { | ||
| 144 | reset_keyboard(); | ||
| 145 | } | ||
| 146 | return false; | ||
| 147 | break; | ||
| 148 | case DEBUG: | ||
| 149 | if (record->event.pressed) { | ||
| 150 | print("\nDEBUG: enabled.\n"); | ||
| 151 | debug_enable = true; | ||
| 152 | } | ||
| 153 | return false; | ||
| 154 | break; | ||
| 155 | #ifdef RGBLIGHT_ENABLE | ||
| 156 | case RGB_TOG: | ||
| 157 | if (record->event.pressed) { | ||
| 158 | rgblight_toggle(); | ||
| 159 | } | ||
| 160 | return false; | ||
| 161 | break; | ||
| 162 | case RGB_MOD: | ||
| 163 | if (record->event.pressed) { | ||
| 164 | rgblight_step(); | ||
| 165 | } | ||
| 166 | return false; | ||
| 167 | break; | ||
| 168 | case RGB_HUI: | ||
| 169 | if (record->event.pressed) { | ||
| 170 | rgblight_increase_hue(); | ||
| 171 | } | ||
| 172 | return false; | ||
| 173 | break; | ||
| 174 | case RGB_HUD: | ||
| 175 | if (record->event.pressed) { | ||
| 176 | rgblight_decrease_hue(); | ||
| 177 | } | ||
| 178 | return false; | ||
| 179 | break; | ||
| 180 | case RGB_SAI: | ||
| 181 | if (record->event.pressed) { | ||
| 182 | rgblight_increase_sat(); | ||
| 183 | } | ||
| 184 | return false; | ||
| 185 | break; | ||
| 186 | case RGB_SAD: | ||
| 187 | if (record->event.pressed) { | ||
| 188 | rgblight_decrease_sat(); | ||
| 189 | } | ||
| 190 | return false; | ||
| 191 | break; | ||
| 192 | case RGB_VAI: | ||
| 193 | if (record->event.pressed) { | ||
| 194 | rgblight_increase_val(); | ||
| 195 | } | ||
| 196 | return false; | ||
| 197 | break; | ||
| 198 | case RGB_VAD: | ||
| 199 | if (record->event.pressed) { | ||
| 200 | rgblight_decrease_val(); | ||
| 201 | } | ||
| 202 | return false; | ||
| 203 | break; | ||
| 204 | #endif | ||
| 205 | case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_NKRO: | ||
| 206 | if (record->event.pressed) { | ||
| 207 | // MAGIC actions (BOOTMAGIC without the boot) | ||
| 208 | if (!eeconfig_is_enabled()) { | ||
| 209 | eeconfig_init(); | ||
| 210 | } | ||
| 211 | /* keymap config */ | ||
| 212 | keymap_config.raw = eeconfig_read_keymap(); | ||
| 213 | switch (keycode) | ||
| 214 | { | ||
| 215 | case MAGIC_SWAP_CONTROL_CAPSLOCK: | ||
| 216 | keymap_config.swap_control_capslock = true; | ||
| 217 | break; | ||
| 218 | case MAGIC_CAPSLOCK_TO_CONTROL: | ||
| 219 | keymap_config.capslock_to_control = true; | ||
| 220 | break; | ||
| 221 | case MAGIC_SWAP_LALT_LGUI: | ||
| 222 | keymap_config.swap_lalt_lgui = true; | ||
| 223 | break; | ||
| 224 | case MAGIC_SWAP_RALT_RGUI: | ||
| 225 | keymap_config.swap_ralt_rgui = true; | ||
| 226 | break; | ||
| 227 | case MAGIC_NO_GUI: | ||
| 228 | keymap_config.no_gui = true; | ||
| 229 | break; | ||
| 230 | case MAGIC_SWAP_GRAVE_ESC: | ||
| 231 | keymap_config.swap_grave_esc = true; | ||
| 232 | break; | ||
| 233 | case MAGIC_SWAP_BACKSLASH_BACKSPACE: | ||
| 234 | keymap_config.swap_backslash_backspace = true; | ||
| 235 | break; | ||
| 236 | case MAGIC_HOST_NKRO: | ||
| 237 | keymap_config.nkro = true; | ||
| 238 | break; | ||
| 239 | case MAGIC_SWAP_ALT_GUI: | ||
| 240 | keymap_config.swap_lalt_lgui = true; | ||
| 241 | keymap_config.swap_ralt_rgui = true; | ||
| 242 | break; | ||
| 243 | case MAGIC_UNSWAP_CONTROL_CAPSLOCK: | ||
| 244 | keymap_config.swap_control_capslock = false; | ||
| 245 | break; | ||
| 246 | case MAGIC_UNCAPSLOCK_TO_CONTROL: | ||
| 247 | keymap_config.capslock_to_control = false; | ||
| 248 | break; | ||
| 249 | case MAGIC_UNSWAP_LALT_LGUI: | ||
| 250 | keymap_config.swap_lalt_lgui = false; | ||
| 251 | break; | ||
| 252 | case MAGIC_UNSWAP_RALT_RGUI: | ||
| 253 | keymap_config.swap_ralt_rgui = false; | ||
| 254 | break; | ||
| 255 | case MAGIC_UNNO_GUI: | ||
| 256 | keymap_config.no_gui = false; | ||
| 257 | break; | ||
| 258 | case MAGIC_UNSWAP_GRAVE_ESC: | ||
| 259 | keymap_config.swap_grave_esc = false; | ||
| 260 | break; | ||
| 261 | case MAGIC_UNSWAP_BACKSLASH_BACKSPACE: | ||
| 262 | keymap_config.swap_backslash_backspace = false; | ||
| 263 | break; | ||
| 264 | case MAGIC_UNHOST_NKRO: | ||
| 265 | keymap_config.nkro = false; | ||
| 266 | break; | ||
| 267 | case MAGIC_UNSWAP_ALT_GUI: | ||
| 268 | keymap_config.swap_lalt_lgui = false; | ||
| 269 | keymap_config.swap_ralt_rgui = false; | ||
| 270 | break; | ||
| 271 | case MAGIC_TOGGLE_NKRO: | ||
| 272 | keymap_config.nkro = !keymap_config.nkro; | ||
| 273 | break; | ||
| 274 | default: | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | eeconfig_update_keymap(keymap_config.raw); | ||
| 278 | clear_keyboard(); // clear to prevent stuck keys | ||
| 279 | |||
| 280 | return false; | ||
| 281 | } | ||
| 282 | break; | ||
| 283 | case KC_LSPO: { | ||
| 284 | if (record->event.pressed) { | ||
| 285 | shift_interrupted[0] = false; | ||
| 286 | register_mods(MOD_BIT(KC_LSFT)); | ||
| 287 | } | ||
| 288 | else { | ||
| 289 | #ifdef DISABLE_SPACE_CADET_ROLLOVER | ||
| 290 | if (get_mods() & MOD_BIT(KC_RSFT)) { | ||
| 291 | shift_interrupted[0] = true; | ||
| 292 | shift_interrupted[1] = true; | ||
| 293 | } | ||
| 294 | #endif | ||
| 295 | if (!shift_interrupted[0]) { | ||
| 296 | register_code(LSPO_KEY); | ||
| 297 | unregister_code(LSPO_KEY); | ||
| 298 | } | ||
| 299 | unregister_mods(MOD_BIT(KC_LSFT)); | ||
| 300 | } | ||
| 301 | return false; | ||
| 302 | // break; | ||
| 303 | } | ||
| 304 | |||
| 305 | case KC_RSPC: { | ||
| 306 | if (record->event.pressed) { | ||
| 307 | shift_interrupted[1] = false; | ||
| 308 | register_mods(MOD_BIT(KC_RSFT)); | ||
| 309 | } | ||
| 310 | else { | ||
| 311 | #ifdef DISABLE_SPACE_CADET_ROLLOVER | ||
| 312 | if (get_mods() & MOD_BIT(KC_LSFT)) { | ||
| 313 | shift_interrupted[0] = true; | ||
| 314 | shift_interrupted[1] = true; | ||
| 315 | } | ||
| 316 | #endif | ||
| 317 | if (!shift_interrupted[1]) { | ||
| 318 | register_code(RSPC_KEY); | ||
| 319 | unregister_code(RSPC_KEY); | ||
| 320 | } | ||
| 321 | unregister_mods(MOD_BIT(KC_RSFT)); | ||
| 322 | } | ||
| 323 | return false; | ||
| 324 | // break; | ||
| 325 | } | ||
| 326 | default: { | ||
| 327 | shift_interrupted[0] = true; | ||
| 328 | shift_interrupted[1] = true; | ||
| 329 | break; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | return process_action_kb(record); | ||
| 334 | } | ||
| 335 | |||
| 336 | const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = { | ||
| 337 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 338 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 339 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 340 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 341 | 0, 1, 1, 1, 1, 1, 1, 0, | ||
| 342 | 1, 1, 1, 1, 0, 0, 0, 0, | ||
| 343 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 344 | 0, 0, 1, 0, 1, 0, 1, 1, | ||
| 345 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 346 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 347 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 348 | 1, 1, 1, 0, 0, 0, 1, 1, | ||
| 349 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 350 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 351 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 352 | 0, 0, 0, 1, 1, 1, 1, 0 | ||
| 353 | }; | ||
| 354 | |||
| 355 | const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = { | ||
| 356 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 357 | KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, | ||
| 358 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 359 | 0, 0, 0, KC_ESC, 0, 0, 0, 0, | ||
| 360 | KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, | ||
| 361 | KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, | ||
| 362 | KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, | ||
| 363 | KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, | ||
| 364 | KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, | ||
| 365 | KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, | ||
| 366 | KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, | ||
| 367 | KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, | ||
| 368 | KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, | ||
| 369 | KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, | ||
| 370 | KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, | ||
| 371 | KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL | ||
| 372 | }; | ||
| 373 | |||
| 374 | /* for users whose OSes are set to Colemak */ | ||
| 375 | #if 0 | ||
| 376 | #include "keymap_colemak.h" | ||
| 377 | |||
| 378 | const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = { | ||
| 379 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 380 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 381 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 382 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 383 | 0, 1, 1, 1, 1, 1, 1, 0, | ||
| 384 | 1, 1, 1, 1, 0, 0, 0, 0, | ||
| 385 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 386 | 0, 0, 1, 0, 1, 0, 1, 1, | ||
| 387 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 388 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 389 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 390 | 1, 1, 1, 0, 0, 0, 1, 1, | ||
| 391 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 392 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 393 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 394 | 0, 0, 0, 1, 1, 1, 1, 0 | ||
| 395 | }; | ||
| 396 | |||
| 397 | const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = { | ||
| 398 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 399 | KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, | ||
| 400 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 401 | 0, 0, 0, KC_ESC, 0, 0, 0, 0, | ||
| 402 | KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, | ||
| 403 | KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, | ||
| 404 | KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, | ||
| 405 | KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, | ||
| 406 | KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G, | ||
| 407 | CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O, | ||
| 408 | CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W, | ||
| 409 | CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, | ||
| 410 | KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G, | ||
| 411 | CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O, | ||
| 412 | CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W, | ||
| 413 | CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL | ||
| 414 | }; | ||
| 415 | |||
| 416 | #endif | ||
| 417 | |||
| 418 | void send_string(const char *str) { | ||
| 419 | while (1) { | ||
| 420 | uint8_t keycode; | ||
| 421 | uint8_t ascii_code = pgm_read_byte(str); | ||
| 422 | if (!ascii_code) break; | ||
| 423 | keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]); | ||
| 424 | if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) { | ||
| 425 | register_code(KC_LSFT); | ||
| 426 | register_code(keycode); | ||
| 427 | unregister_code(keycode); | ||
| 428 | unregister_code(KC_LSFT); | ||
| 429 | } | ||
| 430 | else { | ||
| 431 | register_code(keycode); | ||
| 432 | unregister_code(keycode); | ||
| 433 | } | ||
| 434 | ++str; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) { | ||
| 439 | if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) { | ||
| 440 | layer_on(layer3); | ||
| 441 | } else { | ||
| 442 | layer_off(layer3); | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | void tap_random_base64(void) { | ||
| 447 | #if defined(__AVR_ATmega32U4__) | ||
| 448 | uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64; | ||
| 449 | #else | ||
| 450 | uint8_t key = rand() % 64; | ||
| 451 | #endif | ||
| 452 | switch (key) { | ||
| 453 | case 0 ... 25: | ||
| 454 | register_code(KC_LSFT); | ||
| 455 | register_code(key + KC_A); | ||
| 456 | unregister_code(key + KC_A); | ||
| 457 | unregister_code(KC_LSFT); | ||
| 458 | break; | ||
| 459 | case 26 ... 51: | ||
| 460 | register_code(key - 26 + KC_A); | ||
| 461 | unregister_code(key - 26 + KC_A); | ||
| 462 | break; | ||
| 463 | case 52: | ||
| 464 | register_code(KC_0); | ||
| 465 | unregister_code(KC_0); | ||
| 466 | break; | ||
| 467 | case 53 ... 61: | ||
| 468 | register_code(key - 53 + KC_1); | ||
| 469 | unregister_code(key - 53 + KC_1); | ||
| 470 | break; | ||
| 471 | case 62: | ||
| 472 | register_code(KC_LSFT); | ||
| 473 | register_code(KC_EQL); | ||
| 474 | unregister_code(KC_EQL); | ||
| 475 | unregister_code(KC_LSFT); | ||
| 476 | break; | ||
| 477 | case 63: | ||
| 478 | register_code(KC_SLSH); | ||
| 479 | unregister_code(KC_SLSH); | ||
| 480 | break; | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | void matrix_init_quantum() { | ||
| 485 | #ifdef BACKLIGHT_ENABLE | ||
| 486 | backlight_init_ports(); | ||
| 487 | #endif | ||
| 488 | matrix_init_kb(); | ||
| 489 | } | ||
| 490 | |||
| 491 | void matrix_scan_quantum() { | ||
| 492 | #ifdef AUDIO_ENABLE | ||
| 493 | matrix_scan_music(); | ||
| 494 | #endif | ||
| 495 | |||
| 496 | #ifdef TAP_DANCE_ENABLE | ||
| 497 | matrix_scan_tap_dance(); | ||
| 498 | #endif | ||
| 499 | matrix_scan_kb(); | ||
| 500 | } | ||
| 501 | |||
| 502 | #if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN) | ||
| 503 | |||
| 504 | static const uint8_t backlight_pin = BACKLIGHT_PIN; | ||
| 505 | |||
| 506 | #if BACKLIGHT_PIN == B7 | ||
| 507 | # define COM1x1 COM1C1 | ||
| 508 | # define OCR1x OCR1C | ||
| 509 | #elif BACKLIGHT_PIN == B6 | ||
| 510 | # define COM1x1 COM1B1 | ||
| 511 | # define OCR1x OCR1B | ||
| 512 | #elif BACKLIGHT_PIN == B5 | ||
| 513 | # define COM1x1 COM1A1 | ||
| 514 | # define OCR1x OCR1A | ||
| 515 | #else | ||
| 516 | # error "Backlight pin not supported - use B5, B6, or B7" | ||
| 517 | #endif | ||
| 518 | |||
| 519 | __attribute__ ((weak)) | ||
| 520 | void backlight_init_ports(void) | ||
| 521 | { | ||
| 522 | |||
| 523 | // Setup backlight pin as output and output low. | ||
| 524 | // DDRx |= n | ||
| 525 | _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF); | ||
| 526 | // PORTx &= ~n | ||
| 527 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | ||
| 528 | |||
| 529 | // Use full 16-bit resolution. | ||
| 530 | ICR1 = 0xFFFF; | ||
| 531 | |||
| 532 | // I could write a wall of text here to explain... but TL;DW | ||
| 533 | // Go read the ATmega32u4 datasheet. | ||
| 534 | // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on | ||
| 535 | |||
| 536 | // Pin PB7 = OCR1C (Timer 1, Channel C) | ||
| 537 | // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 | ||
| 538 | // (i.e. start high, go low when counter matches.) | ||
| 539 | // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 | ||
| 540 | // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 | ||
| 541 | |||
| 542 | TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010; | ||
| 543 | TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; | ||
| 544 | |||
| 545 | backlight_init(); | ||
| 546 | #ifdef BACKLIGHT_BREATHING | ||
| 547 | breathing_defaults(); | ||
| 548 | #endif | ||
| 549 | } | ||
| 550 | |||
| 551 | __attribute__ ((weak)) | ||
| 552 | void backlight_set(uint8_t level) | ||
| 553 | { | ||
| 554 | // Prevent backlight blink on lowest level | ||
| 555 | // PORTx &= ~n | ||
| 556 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | ||
| 557 | |||
| 558 | if ( level == 0 ) { | ||
| 559 | // Turn off PWM control on backlight pin, revert to output low. | ||
| 560 | TCCR1A &= ~(_BV(COM1x1)); | ||
| 561 | OCR1x = 0x0; | ||
| 562 | } else if ( level == BACKLIGHT_LEVELS ) { | ||
| 563 | // Turn on PWM control of backlight pin | ||
| 564 | TCCR1A |= _BV(COM1x1); | ||
| 565 | // Set the brightness | ||
| 566 | OCR1x = 0xFFFF; | ||
| 567 | } else { | ||
| 568 | // Turn on PWM control of backlight pin | ||
| 569 | TCCR1A |= _BV(COM1x1); | ||
| 570 | // Set the brightness | ||
| 571 | OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2)); | ||
| 572 | } | ||
| 573 | |||
| 574 | #ifdef BACKLIGHT_BREATHING | ||
| 575 | breathing_intensity_default(); | ||
| 576 | #endif | ||
| 577 | } | ||
| 578 | |||
| 579 | |||
| 580 | #ifdef BACKLIGHT_BREATHING | ||
| 581 | |||
| 582 | #define BREATHING_NO_HALT 0 | ||
| 583 | #define BREATHING_HALT_OFF 1 | ||
| 584 | #define BREATHING_HALT_ON 2 | ||
| 585 | |||
| 586 | static uint8_t breath_intensity; | ||
| 587 | static uint8_t breath_speed; | ||
| 588 | static uint16_t breathing_index; | ||
| 589 | static uint8_t breathing_halt; | ||
| 590 | |||
| 591 | void breathing_enable(void) | ||
| 592 | { | ||
| 593 | if (get_backlight_level() == 0) | ||
| 594 | { | ||
| 595 | breathing_index = 0; | ||
| 596 | } | ||
| 597 | else | ||
| 598 | { | ||
| 599 | // Set breathing_index to be at the midpoint (brightest point) | ||
| 600 | breathing_index = 0x20 << breath_speed; | ||
| 601 | } | ||
| 602 | |||
| 603 | breathing_halt = BREATHING_NO_HALT; | ||
| 604 | |||
| 605 | // Enable breathing interrupt | ||
| 606 | TIMSK1 |= _BV(OCIE1A); | ||
| 607 | } | ||
| 608 | |||
| 609 | void breathing_pulse(void) | ||
| 610 | { | ||
| 611 | if (get_backlight_level() == 0) | ||
| 612 | { | ||
| 613 | breathing_index = 0; | ||
| 614 | } | ||
| 615 | else | ||
| 616 | { | ||
| 617 | // Set breathing_index to be at the midpoint + 1 (brightest point) | ||
| 618 | breathing_index = 0x21 << breath_speed; | ||
| 619 | } | ||
| 620 | |||
| 621 | breathing_halt = BREATHING_HALT_ON; | ||
| 622 | |||
| 623 | // Enable breathing interrupt | ||
| 624 | TIMSK1 |= _BV(OCIE1A); | ||
| 625 | } | ||
| 626 | |||
| 627 | void breathing_disable(void) | ||
| 628 | { | ||
| 629 | // Disable breathing interrupt | ||
| 630 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 631 | backlight_set(get_backlight_level()); | ||
| 632 | } | ||
| 633 | |||
| 634 | void breathing_self_disable(void) | ||
| 635 | { | ||
| 636 | if (get_backlight_level() == 0) | ||
| 637 | { | ||
| 638 | breathing_halt = BREATHING_HALT_OFF; | ||
| 639 | } | ||
| 640 | else | ||
| 641 | { | ||
| 642 | breathing_halt = BREATHING_HALT_ON; | ||
| 643 | } | ||
| 644 | |||
| 645 | //backlight_set(get_backlight_level()); | ||
| 646 | } | ||
| 647 | |||
| 648 | void breathing_toggle(void) | ||
| 649 | { | ||
| 650 | if (!is_breathing()) | ||
| 651 | { | ||
| 652 | if (get_backlight_level() == 0) | ||
| 653 | { | ||
| 654 | breathing_index = 0; | ||
| 655 | } | ||
| 656 | else | ||
| 657 | { | ||
| 658 | // Set breathing_index to be at the midpoint + 1 (brightest point) | ||
| 659 | breathing_index = 0x21 << breath_speed; | ||
| 660 | } | ||
| 661 | |||
| 662 | breathing_halt = BREATHING_NO_HALT; | ||
| 663 | } | ||
| 664 | |||
| 665 | // Toggle breathing interrupt | ||
| 666 | TIMSK1 ^= _BV(OCIE1A); | ||
| 667 | |||
| 668 | // Restore backlight level | ||
| 669 | if (!is_breathing()) | ||
| 670 | { | ||
| 671 | backlight_set(get_backlight_level()); | ||
| 672 | } | ||
| 673 | } | ||
| 674 | |||
| 675 | bool is_breathing(void) | ||
| 676 | { | ||
| 677 | return (TIMSK1 && _BV(OCIE1A)); | ||
| 678 | } | ||
| 679 | |||
| 680 | void breathing_intensity_default(void) | ||
| 681 | { | ||
| 682 | //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS); | ||
| 683 | breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2)); | ||
| 684 | } | ||
| 685 | |||
| 686 | void breathing_intensity_set(uint8_t value) | ||
| 687 | { | ||
| 688 | breath_intensity = value; | ||
| 689 | } | ||
| 690 | |||
| 691 | void breathing_speed_default(void) | ||
| 692 | { | ||
| 693 | breath_speed = 4; | ||
| 694 | } | ||
| 695 | |||
| 696 | void breathing_speed_set(uint8_t value) | ||
| 697 | { | ||
| 698 | bool is_breathing_now = is_breathing(); | ||
| 699 | uint8_t old_breath_speed = breath_speed; | ||
| 700 | |||
| 701 | if (is_breathing_now) | ||
| 702 | { | ||
| 703 | // Disable breathing interrupt | ||
| 704 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 705 | } | ||
| 706 | |||
| 707 | breath_speed = value; | ||
| 708 | |||
| 709 | if (is_breathing_now) | ||
| 710 | { | ||
| 711 | // Adjust index to account for new speed | ||
| 712 | breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed; | ||
| 713 | |||
| 714 | // Enable breathing interrupt | ||
| 715 | TIMSK1 |= _BV(OCIE1A); | ||
| 716 | } | ||
| 717 | |||
| 718 | } | ||
| 719 | |||
| 720 | void breathing_speed_inc(uint8_t value) | ||
| 721 | { | ||
| 722 | if ((uint16_t)(breath_speed - value) > 10 ) | ||
| 723 | { | ||
| 724 | breathing_speed_set(0); | ||
| 725 | } | ||
| 726 | else | ||
| 727 | { | ||
| 728 | breathing_speed_set(breath_speed - value); | ||
| 729 | } | ||
| 730 | } | ||
| 731 | |||
| 732 | void breathing_speed_dec(uint8_t value) | ||
| 733 | { | ||
| 734 | if ((uint16_t)(breath_speed + value) > 10 ) | ||
| 735 | { | ||
| 736 | breathing_speed_set(10); | ||
| 737 | } | ||
| 738 | else | ||
| 739 | { | ||
| 740 | breathing_speed_set(breath_speed + value); | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | void breathing_defaults(void) | ||
| 745 | { | ||
| 746 | breathing_intensity_default(); | ||
| 747 | breathing_speed_default(); | ||
| 748 | breathing_halt = BREATHING_NO_HALT; | ||
| 749 | } | ||
| 750 | |||
| 751 | /* Breathing Sleep LED brighness(PWM On period) table | ||
| 752 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 753 | * | ||
| 754 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
| 755 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
| 756 | */ | ||
| 757 | static const uint8_t breathing_table[64] PROGMEM = { | ||
| 758 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, | ||
| 759 | 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, | ||
| 760 | 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, | ||
| 761 | 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 762 | }; | ||
| 763 | |||
| 764 | ISR(TIMER1_COMPA_vect) | ||
| 765 | { | ||
| 766 | // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity; | ||
| 767 | |||
| 768 | |||
| 769 | uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F; | ||
| 770 | |||
| 771 | if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F))) | ||
| 772 | { | ||
| 773 | // Disable breathing interrupt | ||
| 774 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 775 | } | ||
| 776 | |||
| 777 | OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity; | ||
| 778 | |||
| 779 | } | ||
| 780 | |||
| 781 | |||
| 782 | |||
| 783 | #endif // breathing | ||
| 784 | |||
| 785 | #else // backlight | ||
| 786 | |||
| 787 | __attribute__ ((weak)) | ||
| 788 | void backlight_init_ports(void) | ||
| 789 | { | ||
| 790 | |||
| 791 | } | ||
| 792 | |||
| 793 | __attribute__ ((weak)) | ||
| 794 | void backlight_set(uint8_t level) | ||
| 795 | { | ||
| 796 | |||
| 797 | } | ||
| 798 | |||
| 799 | #endif // backlight | ||
| 800 | |||
| 801 | |||
| 802 | |||
| 803 | __attribute__ ((weak)) | ||
| 804 | void led_set_user(uint8_t usb_led) { | ||
| 805 | |||
| 806 | } | ||
| 807 | |||
| 808 | __attribute__ ((weak)) | ||
| 809 | void led_set_kb(uint8_t usb_led) { | ||
| 810 | led_set_user(usb_led); | ||
| 811 | } | ||
| 812 | |||
| 813 | __attribute__ ((weak)) | ||
| 814 | void led_init_ports(void) | ||
| 815 | { | ||
| 816 | |||
| 817 | } | ||
| 818 | |||
| 819 | __attribute__ ((weak)) | ||
| 820 | void led_set(uint8_t usb_led) | ||
| 821 | { | ||
| 822 | |||
| 823 | // Example LED Code | ||
| 824 | // | ||
| 825 | // // Using PE6 Caps Lock LED | ||
| 826 | // if (usb_led & (1<<USB_LED_CAPS_LOCK)) | ||
| 827 | // { | ||
| 828 | // // Output high. | ||
| 829 | // DDRE |= (1<<6); | ||
| 830 | // PORTE |= (1<<6); | ||
| 831 | // } | ||
| 832 | // else | ||
| 833 | // { | ||
| 834 | // // Output low. | ||
| 835 | // DDRE &= ~(1<<6); | ||
| 836 | // PORTE &= ~(1<<6); | ||
| 837 | // } | ||
| 838 | |||
| 839 | led_set_kb(usb_led); | ||
| 840 | } | ||
| 841 | |||
| 842 | |||
| 843 | //------------------------------------------------------------------------------ | ||
| 844 | // Override these functions in your keymap file to play different tunes on | ||
| 845 | // different events such as startup and bootloader jump | ||
| 846 | |||
| 847 | __attribute__ ((weak)) | ||
| 848 | void startup_user() {} | ||
| 849 | |||
| 850 | __attribute__ ((weak)) | ||
| 851 | void shutdown_user() {} | ||
| 852 | |||
| 853 | //------------------------------------------------------------------------------ | ||
diff --git a/quantum/quantum.h b/quantum/quantum.h new file mode 100644 index 000000000..0c6046649 --- /dev/null +++ b/quantum/quantum.h | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | #ifndef QUANTUM_H | ||
| 2 | #define QUANTUM_H | ||
| 3 | |||
| 4 | #if defined(__AVR__) | ||
| 5 | #include <avr/pgmspace.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | #include <avr/interrupt.h> | ||
| 8 | #endif | ||
| 9 | #include "wait.h" | ||
| 10 | #include "matrix.h" | ||
| 11 | #include "keymap.h" | ||
| 12 | #ifdef BACKLIGHT_ENABLE | ||
| 13 | #include "backlight.h" | ||
| 14 | #endif | ||
| 15 | #ifdef RGBLIGHT_ENABLE | ||
| 16 | #include "rgblight.h" | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include "action_layer.h" | ||
| 20 | #include "eeconfig.h" | ||
| 21 | #include <stddef.h> | ||
| 22 | #include "bootloader.h" | ||
| 23 | #include "timer.h" | ||
| 24 | #include "config_common.h" | ||
| 25 | #include "led.h" | ||
| 26 | #include "action_util.h" | ||
| 27 | #include <stdlib.h> | ||
| 28 | #include "print.h" | ||
| 29 | |||
| 30 | |||
| 31 | extern uint32_t default_layer_state; | ||
| 32 | |||
| 33 | #ifndef NO_ACTION_LAYER | ||
| 34 | extern uint32_t layer_state; | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #ifdef MIDI_ENABLE | ||
| 38 | #include <lufa.h> | ||
| 39 | #include "process_midi.h" | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #ifdef AUDIO_ENABLE | ||
| 43 | #include "audio.h" | ||
| 44 | #include "process_music.h" | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #ifndef DISABLE_LEADER | ||
| 48 | #include "process_leader.h" | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #define DISABLE_CHORDING | ||
| 52 | #ifndef DISABLE_CHORDING | ||
| 53 | #include "process_chording.h" | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #ifdef UNICODE_ENABLE | ||
| 57 | #include "process_unicode.h" | ||
| 58 | #endif | ||
| 59 | |||
| 60 | #include "process_tap_dance.h" | ||
| 61 | |||
| 62 | #define SEND_STRING(str) send_string(PSTR(str)) | ||
| 63 | void send_string(const char *str); | ||
| 64 | |||
| 65 | // For tri-layer | ||
| 66 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); | ||
| 67 | |||
| 68 | void tap_random_base64(void); | ||
| 69 | |||
| 70 | #define IS_LAYER_ON(layer) (layer_state & (1UL << (layer))) | ||
| 71 | #define IS_LAYER_OFF(layer) (~layer_state & (1UL << (layer))) | ||
| 72 | |||
| 73 | void matrix_init_kb(void); | ||
| 74 | void matrix_scan_kb(void); | ||
| 75 | void matrix_init_user(void); | ||
| 76 | void matrix_scan_user(void); | ||
| 77 | bool process_action_kb(keyrecord_t *record); | ||
| 78 | bool process_record_kb(uint16_t keycode, keyrecord_t *record); | ||
| 79 | bool process_record_user(uint16_t keycode, keyrecord_t *record); | ||
| 80 | |||
| 81 | void reset_keyboard(void); | ||
| 82 | |||
| 83 | void startup_user(void); | ||
| 84 | void shutdown_user(void); | ||
| 85 | |||
| 86 | void register_code16 (uint16_t code); | ||
| 87 | void unregister_code16 (uint16_t code); | ||
| 88 | |||
| 89 | #ifdef BACKLIGHT_ENABLE | ||
| 90 | void backlight_init_ports(void); | ||
| 91 | |||
| 92 | #ifdef BACKLIGHT_BREATHING | ||
| 93 | void breathing_enable(void); | ||
| 94 | void breathing_pulse(void); | ||
| 95 | void breathing_disable(void); | ||
| 96 | void breathing_self_disable(void); | ||
| 97 | void breathing_toggle(void); | ||
| 98 | bool is_breathing(void); | ||
| 99 | |||
| 100 | void breathing_defaults(void); | ||
| 101 | void breathing_intensity_default(void); | ||
| 102 | void breathing_speed_default(void); | ||
| 103 | void breathing_speed_set(uint8_t value); | ||
| 104 | void breathing_speed_inc(uint8_t value); | ||
| 105 | void breathing_speed_dec(uint8_t value); | ||
| 106 | #endif | ||
| 107 | |||
| 108 | #endif | ||
| 109 | |||
| 110 | void led_set_user(uint8_t usb_led); | ||
| 111 | void led_set_kb(uint8_t usb_led); | ||
| 112 | |||
| 113 | #endif | ||
diff --git a/quantum/quantum.mk b/quantum/quantum.mk deleted file mode 100644 index de93af7e8..000000000 --- a/quantum/quantum.mk +++ /dev/null | |||
| @@ -1,53 +0,0 @@ | |||
| 1 | QUANTUM_DIR = quantum | ||
| 2 | |||
| 3 | # # project specific files | ||
| 4 | SRC += $(QUANTUM_DIR)/keymap_common.c \ | ||
| 5 | $(QUANTUM_DIR)/led.c | ||
| 6 | |||
| 7 | # ifdef KEYMAP_FILE | ||
| 8 | # ifneq (,$(shell grep USING_MIDI '$(KEYMAP_FILE)')) | ||
| 9 | # MIDI_ENABLE=yes | ||
| 10 | # $(info * Overriding MIDI_ENABLE setting - $(KEYMAP_FILE) requires it) | ||
| 11 | # endif | ||
| 12 | # ifneq (,$(shell grep USING_UNICODE '$(KEYMAP_FILE)')) | ||
| 13 | # UNICODE_ENABLE=yes | ||
| 14 | # $(info * Overriding UNICODE_ENABLE setting - $(KEYMAP_FILE) requires it) | ||
| 15 | # endif | ||
| 16 | # ifneq (,$(shell grep USING_BACKLIGHT '$(KEYMAP_FILE)')) | ||
| 17 | # BACKLIGHT_ENABLE=yes | ||
| 18 | # $(info * Overriding BACKLIGHT_ENABLE setting - $(KEYMAP_FILE) requires it) | ||
| 19 | # endif | ||
| 20 | # endif | ||
| 21 | |||
| 22 | ifndef CUSTOM_MATRIX | ||
| 23 | SRC += $(QUANTUM_DIR)/matrix.c | ||
| 24 | endif | ||
| 25 | |||
| 26 | ifdef MIDI_ENABLE | ||
| 27 | SRC += $(QUANTUM_DIR)/keymap_midi.c | ||
| 28 | endif | ||
| 29 | |||
| 30 | ifdef AUDIO_ENABLE | ||
| 31 | SRC += $(QUANTUM_DIR)/audio.c | ||
| 32 | endif | ||
| 33 | |||
| 34 | ifdef UNICODE_ENABLE | ||
| 35 | SRC += $(QUANTUM_DIR)/keymap_unicode.c | ||
| 36 | endif | ||
| 37 | |||
| 38 | ifdef RGBLIGHT_ENABLE | ||
| 39 | SRC += $(QUANTUM_DIR)/light_ws2812.c | ||
| 40 | SRC += $(QUANTUM_DIR)/rgblight.c | ||
| 41 | OPT_DEFS += -DRGBLIGHT_ENABLE | ||
| 42 | endif | ||
| 43 | |||
| 44 | # Optimize size but this may cause error "relocation truncated to fit" | ||
| 45 | #EXTRALDFLAGS = -Wl,--relax | ||
| 46 | |||
| 47 | # Search Path | ||
| 48 | VPATH += $(TOP_DIR)/$(QUANTUM_DIR) | ||
| 49 | |||
| 50 | include $(TMK_DIR)/protocol/lufa.mk | ||
| 51 | |||
| 52 | include $(TMK_DIR)/common.mk | ||
| 53 | include $(TMK_DIR)/rules.mk | ||
diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 2215cf5cd..d550c5866 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c | |||
| @@ -6,29 +6,65 @@ | |||
| 6 | #include "rgblight.h" | 6 | #include "rgblight.h" |
| 7 | #include "debug.h" | 7 | #include "debug.h" |
| 8 | 8 | ||
| 9 | // Lightness curve using the CIE 1931 lightness formula | ||
| 10 | //Generated by the python script provided in http://jared.geek.nz/2013/feb/linear-led-pwm | ||
| 9 | const uint8_t DIM_CURVE[] PROGMEM = { | 11 | const uint8_t DIM_CURVE[] PROGMEM = { |
| 10 | 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, | 12 | 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, |
| 11 | 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, | 13 | 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, |
| 12 | 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, | 14 | 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, |
| 13 | 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, | 15 | 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, |
| 14 | 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, | 16 | 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, |
| 15 | 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, | 17 | 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, |
| 16 | 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, | 18 | 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, |
| 17 | 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, | 19 | 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, |
| 18 | 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, | 20 | 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, |
| 19 | 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, | 21 | 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, |
| 20 | 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, | 22 | 28, 28, 29, 29, 30, 31, 31, 32, 32, 33, |
| 21 | 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, | 23 | 34, 34, 35, 36, 37, 37, 38, 39, 39, 40, |
| 22 | 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, | 24 | 41, 42, 43, 43, 44, 45, 46, 47, 47, 48, |
| 23 | 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, | 25 | 49, 50, 51, 52, 53, 54, 54, 55, 56, 57, |
| 24 | 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, | 26 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, |
| 25 | 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, | 27 | 68, 70, 71, 72, 73, 74, 75, 76, 77, 79, |
| 28 | 80, 81, 82, 83, 85, 86, 87, 88, 90, 91, | ||
| 29 | 92, 94, 95, 96, 98, 99, 100, 102, 103, 105, | ||
| 30 | 106, 108, 109, 110, 112, 113, 115, 116, 118, 120, | ||
| 31 | 121, 123, 124, 126, 128, 129, 131, 132, 134, 136, | ||
| 32 | 138, 139, 141, 143, 145, 146, 148, 150, 152, 154, | ||
| 33 | 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, | ||
| 34 | 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, | ||
| 35 | 196, 198, 200, 202, 204, 207, 209, 211, 214, 216, | ||
| 36 | 218, 220, 223, 225, 228, 230, 232, 235, 237, 240, | ||
| 37 | 242, 245, 247, 250, 252, 255, | ||
| 38 | }; | ||
| 39 | |||
| 40 | const uint8_t RGBLED_BREATHING_TABLE[] PROGMEM = { | ||
| 41 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, | ||
| 42 | 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, | ||
| 43 | 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, | ||
| 44 | 79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, | ||
| 45 | 127, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, 173, | ||
| 46 | 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, 213, 215, | ||
| 47 | 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241, 243, 244, | ||
| 48 | 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, | ||
| 49 | 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, 248, 246, | ||
| 50 | 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220, | ||
| 51 | 218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179, | ||
| 52 | 176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, 134, 131, | ||
| 53 | 128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 93, 90, 88, 85, 82, | ||
| 54 | 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, | ||
| 55 | 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, | ||
| 56 | 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0 | ||
| 26 | }; | 57 | }; |
| 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}; | 58 | |
| 59 | __attribute__ ((weak)) | ||
| 28 | const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; | 60 | const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; |
| 61 | __attribute__ ((weak)) | ||
| 29 | const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; | 62 | const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; |
| 63 | __attribute__ ((weak)) | ||
| 30 | const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; | 64 | const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; |
| 65 | __attribute__ ((weak)) | ||
| 31 | const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; | 66 | const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; |
| 67 | __attribute__ ((weak)) | ||
| 32 | const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; | 68 | const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; |
| 33 | 69 | ||
| 34 | rgblight_config_t rgblight_config; | 70 | rgblight_config_t rgblight_config; |
| @@ -38,63 +74,54 @@ uint8_t rgblight_inited = 0; | |||
| 38 | 74 | ||
| 39 | 75 | ||
| 40 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) { | 76 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) { |
| 41 | /* convert hue, saturation and brightness ( HSB/HSV ) to RGB | 77 | uint8_t r = 0, g = 0, b = 0, base, color; |
| 42 | The DIM_CURVE is used only on brightness/value and on saturation (inverted). | 78 | |
| 43 | This looks the most natural. | 79 | if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. |
| 44 | */ | 80 | r = val; |
| 45 | uint8_t r, g, b; | 81 | g = val; |
| 46 | 82 | b = val; | |
| 47 | val = pgm_read_byte(&DIM_CURVE[val]); | 83 | } else { |
| 48 | sat = 255 - pgm_read_byte(&DIM_CURVE[255 - sat]); | 84 | base = ((255 - sat) * val) >> 8; |
| 49 | 85 | color = (val - base) * (hue % 60) / 60; | |
| 50 | uint8_t base; | 86 | |
| 51 | 87 | switch (hue / 60) { | |
| 52 | if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. | 88 | case 0: |
| 53 | r = val; | 89 | r = val; |
| 54 | g = val; | 90 | g = base + color; |
| 55 | b = val; | 91 | b = base; |
| 56 | } else { | 92 | break; |
| 57 | base = ((255 - sat) * val) >> 8; | 93 | case 1: |
| 58 | 94 | r = val - color; | |
| 59 | switch (hue / 60) { | 95 | g = val; |
| 60 | case 0: | 96 | b = base; |
| 61 | r = val; | 97 | break; |
| 62 | g = (((val - base)*hue) / 60) + base; | 98 | case 2: |
| 63 | b = base; | 99 | r = base; |
| 64 | break; | 100 | g = val; |
| 65 | 101 | b = base + color; | |
| 66 | case 1: | 102 | break; |
| 67 | r = (((val - base)*(60 - (hue % 60))) / 60) + base; | 103 | case 3: |
| 68 | g = val; | 104 | r = base; |
| 69 | b = base; | 105 | g = val - color; |
| 70 | break; | 106 | b = val; |
| 71 | 107 | break; | |
| 72 | case 2: | 108 | case 4: |
| 73 | r = base; | 109 | r = base + color; |
| 74 | g = val; | 110 | g = base; |
| 75 | b = (((val - base)*(hue % 60)) / 60) + base; | 111 | b = val; |
| 76 | break; | 112 | break; |
| 77 | 113 | case 5: | |
| 78 | case 3: | 114 | r = val; |
| 79 | r = base; | 115 | g = base; |
| 80 | g = (((val - base)*(60 - (hue % 60))) / 60) + base; | 116 | b = val - color; |
| 81 | b = val; | 117 | break; |
| 82 | break; | 118 | } |
| 83 | 119 | } | |
| 84 | case 4: | 120 | r = pgm_read_byte(&DIM_CURVE[r]); |
| 85 | r = (((val - base)*(hue % 60)) / 60) + base; | 121 | g = pgm_read_byte(&DIM_CURVE[g]); |
| 86 | g = base; | 122 | b = pgm_read_byte(&DIM_CURVE[b]); |
| 87 | b = val; | 123 | |
| 88 | break; | 124 | setrgb(r, g, b, led1); |
| 89 | |||
| 90 | case 5: | ||
| 91 | r = val; | ||
| 92 | g = base; | ||
| 93 | b = (((val - base)*(60 - (hue % 60))) / 60) + base; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | setrgb(r,g,b, led1); | ||
| 98 | } | 125 | } |
| 99 | 126 | ||
| 100 | void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { | 127 | void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { |
| @@ -107,46 +134,48 @@ void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { | |||
| 107 | uint32_t eeconfig_read_rgblight(void) { | 134 | uint32_t eeconfig_read_rgblight(void) { |
| 108 | return eeprom_read_dword(EECONFIG_RGBLIGHT); | 135 | return eeprom_read_dword(EECONFIG_RGBLIGHT); |
| 109 | } | 136 | } |
| 110 | void eeconfig_write_rgblight(uint32_t val) { | 137 | void eeconfig_update_rgblight(uint32_t val) { |
| 111 | eeprom_write_dword(EECONFIG_RGBLIGHT, val); | 138 | eeprom_update_dword(EECONFIG_RGBLIGHT, val); |
| 112 | } | 139 | } |
| 113 | void eeconfig_write_rgblight_default(void) { | 140 | void eeconfig_update_rgblight_default(void) { |
| 114 | dprintf("eeconfig_write_rgblight_default\n"); | 141 | dprintf("eeconfig_update_rgblight_default\n"); |
| 115 | rgblight_config.enable = 1; | 142 | rgblight_config.enable = 1; |
| 116 | rgblight_config.mode = 1; | 143 | rgblight_config.mode = 1; |
| 117 | rgblight_config.hue = 200; | 144 | rgblight_config.hue = 200; |
| 118 | rgblight_config.sat = 204; | 145 | rgblight_config.sat = 204; |
| 119 | rgblight_config.val = 204; | 146 | rgblight_config.val = 204; |
| 120 | eeconfig_write_rgblight(rgblight_config.raw); | 147 | eeconfig_update_rgblight(rgblight_config.raw); |
| 121 | } | 148 | } |
| 122 | void eeconfig_debug_rgblight(void) { | 149 | void eeconfig_debug_rgblight(void) { |
| 123 | dprintf("rgblight_config eprom\n"); | 150 | dprintf("rgblight_config eprom\n"); |
| 124 | dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); | 151 | dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); |
| 125 | dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); | 152 | dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); |
| 126 | dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); | 153 | dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); |
| 127 | dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); | 154 | dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); |
| 128 | dprintf("rgblight_config.val = %d\n", rgblight_config.val); | 155 | dprintf("rgblight_config.val = %d\n", rgblight_config.val); |
| 129 | } | 156 | } |
| 130 | 157 | ||
| 131 | void rgblight_init(void) { | 158 | void rgblight_init(void) { |
| 132 | debug_enable = 1; // Debug ON! | 159 | debug_enable = 1; // Debug ON! |
| 133 | dprintf("rgblight_init called.\n"); | 160 | dprintf("rgblight_init called.\n"); |
| 134 | rgblight_inited = 1; | 161 | rgblight_inited = 1; |
| 135 | dprintf("rgblight_init start!\n"); | 162 | dprintf("rgblight_init start!\n"); |
| 136 | if (!eeconfig_is_enabled()) { | 163 | if (!eeconfig_is_enabled()) { |
| 137 | dprintf("rgblight_init eeconfig is not enabled.\n"); | 164 | dprintf("rgblight_init eeconfig is not enabled.\n"); |
| 138 | eeconfig_init(); | 165 | eeconfig_init(); |
| 139 | eeconfig_write_rgblight_default(); | 166 | eeconfig_update_rgblight_default(); |
| 140 | } | 167 | } |
| 141 | rgblight_config.raw = eeconfig_read_rgblight(); | 168 | rgblight_config.raw = eeconfig_read_rgblight(); |
| 142 | if (!rgblight_config.mode) { | 169 | if (!rgblight_config.mode) { |
| 143 | dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); | 170 | dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); |
| 144 | eeconfig_write_rgblight_default(); | 171 | eeconfig_update_rgblight_default(); |
| 145 | rgblight_config.raw = eeconfig_read_rgblight(); | 172 | rgblight_config.raw = eeconfig_read_rgblight(); |
| 146 | } | 173 | } |
| 147 | eeconfig_debug_rgblight(); // display current eeprom values | 174 | eeconfig_debug_rgblight(); // display current eeprom values |
| 148 | 175 | ||
| 149 | rgblight_timer_init(); // setup the timer | 176 | #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) |
| 177 | rgblight_timer_init(); // setup the timer | ||
| 178 | #endif | ||
| 150 | 179 | ||
| 151 | if (rgblight_config.enable) { | 180 | if (rgblight_config.enable) { |
| 152 | rgblight_mode(rgblight_config.mode); | 181 | rgblight_mode(rgblight_config.mode); |
| @@ -154,352 +183,376 @@ void rgblight_init(void) { | |||
| 154 | } | 183 | } |
| 155 | 184 | ||
| 156 | void rgblight_increase(void) { | 185 | void rgblight_increase(void) { |
| 157 | uint8_t mode; | 186 | uint8_t mode = 0; |
| 158 | if (rgblight_config.mode < RGBLIGHT_MODES) { | 187 | if (rgblight_config.mode < RGBLIGHT_MODES) { |
| 159 | mode = rgblight_config.mode + 1; | 188 | mode = rgblight_config.mode + 1; |
| 160 | } | 189 | } |
| 161 | rgblight_mode(mode); | 190 | rgblight_mode(mode); |
| 162 | } | 191 | } |
| 163 | |||
| 164 | void rgblight_decrease(void) { | 192 | void rgblight_decrease(void) { |
| 165 | uint8_t mode; | 193 | uint8_t mode = 0; |
| 166 | if (rgblight_config.mode > 1) { //mode will never < 1, if mode is less than 1, eeprom need to be initialized. | 194 | // Mode will never be < 1. If it ever is, eeprom needs to be initialized. |
| 167 | mode = rgblight_config.mode-1; | 195 | if (rgblight_config.mode > 1) { |
| 196 | mode = rgblight_config.mode - 1; | ||
| 168 | } | 197 | } |
| 169 | rgblight_mode(mode); | 198 | rgblight_mode(mode); |
| 170 | } | 199 | } |
| 171 | |||
| 172 | void rgblight_step(void) { | 200 | void rgblight_step(void) { |
| 173 | uint8_t mode; | 201 | uint8_t mode = 0; |
| 174 | mode = rgblight_config.mode + 1; | 202 | mode = rgblight_config.mode + 1; |
| 175 | if (mode > RGBLIGHT_MODES) { | 203 | if (mode > RGBLIGHT_MODES) { |
| 176 | mode = 1; | 204 | mode = 1; |
| 177 | } | 205 | } |
| 178 | rgblight_mode(mode); | 206 | rgblight_mode(mode); |
| 179 | } | 207 | } |
| 180 | 208 | ||
| 181 | void rgblight_mode(uint8_t mode) { | 209 | void rgblight_mode(uint8_t mode) { |
| 182 | if (!rgblight_config.enable) { | 210 | if (!rgblight_config.enable) { |
| 183 | return; | 211 | return; |
| 184 | } | 212 | } |
| 185 | if (mode<1) { | 213 | if (mode < 1) { |
| 186 | rgblight_config.mode = 1; | 214 | rgblight_config.mode = 1; |
| 187 | } else if (mode > RGBLIGHT_MODES) { | 215 | } else if (mode > RGBLIGHT_MODES) { |
| 188 | rgblight_config.mode = RGBLIGHT_MODES; | 216 | rgblight_config.mode = RGBLIGHT_MODES; |
| 189 | } else { | 217 | } else { |
| 190 | rgblight_config.mode = mode; | 218 | rgblight_config.mode = mode; |
| 191 | } | 219 | } |
| 192 | eeconfig_write_rgblight(rgblight_config.raw); | 220 | eeconfig_update_rgblight(rgblight_config.raw); |
| 193 | dprintf("rgblight mode: %u\n", rgblight_config.mode); | 221 | xprintf("rgblight mode: %u\n", rgblight_config.mode); |
| 194 | if (rgblight_config.mode == 1) { | 222 | if (rgblight_config.mode == 1) { |
| 195 | rgblight_timer_disable(); | 223 | #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) |
| 196 | } else if (rgblight_config.mode >=2 && rgblight_config.mode <=23) { | 224 | rgblight_timer_disable(); |
| 197 | // MODE 2-5, breathing | 225 | #endif |
| 198 | // MODE 6-8, rainbow mood | 226 | } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 23) { |
| 199 | // MODE 9-14, rainbow swirl | 227 | // MODE 2-5, breathing |
| 200 | // MODE 15-20, snake | 228 | // MODE 6-8, rainbow mood |
| 201 | // MODE 21-23, knight | 229 | // MODE 9-14, rainbow swirl |
| 202 | rgblight_timer_enable(); | 230 | // MODE 15-20, snake |
| 203 | } | 231 | // MODE 21-23, knight |
| 232 | |||
| 233 | #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) | ||
| 234 | rgblight_timer_enable(); | ||
| 235 | #endif | ||
| 236 | } | ||
| 204 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | 237 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); |
| 205 | } | 238 | } |
| 206 | 239 | ||
| 207 | void rgblight_toggle(void) { | 240 | void rgblight_toggle(void) { |
| 208 | rgblight_config.enable ^= 1; | 241 | rgblight_config.enable ^= 1; |
| 209 | eeconfig_write_rgblight(rgblight_config.raw); | 242 | eeconfig_update_rgblight(rgblight_config.raw); |
| 210 | dprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable); | 243 | xprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable); |
| 211 | if (rgblight_config.enable) { | 244 | if (rgblight_config.enable) { |
| 212 | rgblight_mode(rgblight_config.mode); | 245 | rgblight_mode(rgblight_config.mode); |
| 213 | } else { | 246 | } else { |
| 214 | rgblight_timer_disable(); | 247 | #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) |
| 215 | _delay_ms(50); | 248 | rgblight_timer_disable(); |
| 216 | rgblight_set(); | 249 | #endif |
| 217 | } | 250 | _delay_ms(50); |
| 251 | rgblight_set(); | ||
| 252 | } | ||
| 218 | } | 253 | } |
| 219 | 254 | ||
| 220 | 255 | ||
| 221 | void rgblight_increase_hue(void){ | 256 | void rgblight_increase_hue(void) { |
| 222 | uint16_t hue; | 257 | uint16_t hue; |
| 223 | hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360; | 258 | hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360; |
| 224 | rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); | 259 | rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); |
| 225 | } | 260 | } |
| 226 | void rgblight_decrease_hue(void){ | 261 | void rgblight_decrease_hue(void) { |
| 227 | uint16_t hue; | 262 | uint16_t hue; |
| 228 | if (rgblight_config.hue-RGBLIGHT_HUE_STEP <0 ) { | 263 | if (rgblight_config.hue-RGBLIGHT_HUE_STEP < 0) { |
| 229 | hue = (rgblight_config.hue+360-RGBLIGHT_HUE_STEP) % 360; | 264 | hue = (rgblight_config.hue + 360 - RGBLIGHT_HUE_STEP) % 360; |
| 230 | } else { | 265 | } else { |
| 231 | hue = (rgblight_config.hue-RGBLIGHT_HUE_STEP) % 360; | 266 | hue = (rgblight_config.hue - RGBLIGHT_HUE_STEP) % 360; |
| 232 | } | 267 | } |
| 233 | rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); | 268 | rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); |
| 234 | } | 269 | } |
| 235 | void rgblight_increase_sat(void) { | 270 | void rgblight_increase_sat(void) { |
| 236 | uint8_t sat; | 271 | uint8_t sat; |
| 237 | if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) { | 272 | if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) { |
| 238 | sat = 255; | 273 | sat = 255; |
| 239 | } else { | 274 | } else { |
| 240 | sat = rgblight_config.sat+RGBLIGHT_SAT_STEP; | 275 | sat = rgblight_config.sat + RGBLIGHT_SAT_STEP; |
| 241 | } | 276 | } |
| 242 | rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); | 277 | rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); |
| 243 | } | 278 | } |
| 244 | void rgblight_decrease_sat(void){ | 279 | void rgblight_decrease_sat(void) { |
| 245 | uint8_t sat; | 280 | uint8_t sat; |
| 246 | if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) { | 281 | if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) { |
| 247 | sat = 0; | 282 | sat = 0; |
| 248 | } else { | 283 | } else { |
| 249 | sat = rgblight_config.sat-RGBLIGHT_SAT_STEP; | 284 | sat = rgblight_config.sat - RGBLIGHT_SAT_STEP; |
| 250 | } | 285 | } |
| 251 | rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); | 286 | rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); |
| 252 | } | 287 | } |
| 253 | void rgblight_increase_val(void){ | 288 | void rgblight_increase_val(void) { |
| 254 | uint8_t val; | 289 | uint8_t val; |
| 255 | if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) { | 290 | if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) { |
| 256 | val = 255; | 291 | val = 255; |
| 257 | } else { | 292 | } else { |
| 258 | val = rgblight_config.val+RGBLIGHT_VAL_STEP; | 293 | val = rgblight_config.val + RGBLIGHT_VAL_STEP; |
| 259 | } | 294 | } |
| 260 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); | 295 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); |
| 261 | } | 296 | } |
| 262 | void rgblight_decrease_val(void) { | 297 | void rgblight_decrease_val(void) { |
| 263 | uint8_t val; | 298 | uint8_t val; |
| 264 | if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) { | 299 | if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) { |
| 265 | val = 0; | 300 | val = 0; |
| 266 | } else { | 301 | } else { |
| 267 | val = rgblight_config.val-RGBLIGHT_VAL_STEP; | 302 | val = rgblight_config.val - RGBLIGHT_VAL_STEP; |
| 268 | } | 303 | } |
| 269 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); | 304 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); |
| 270 | } | 305 | } |
| 271 | 306 | ||
| 272 | void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val){ | 307 | void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { |
| 273 | inmem_config.raw = rgblight_config.raw; | 308 | inmem_config.raw = rgblight_config.raw; |
| 274 | if (rgblight_config.enable) { | 309 | if (rgblight_config.enable) { |
| 275 | struct cRGB tmp_led; | 310 | struct cRGB tmp_led; |
| 276 | sethsv(hue, sat, val, &tmp_led); | 311 | sethsv(hue, sat, val, &tmp_led); |
| 277 | inmem_config.hue = hue; | 312 | inmem_config.hue = hue; |
| 278 | inmem_config.sat = sat; | 313 | inmem_config.sat = sat; |
| 279 | inmem_config.val = val; | 314 | inmem_config.val = val; |
| 280 | // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val); | 315 | // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val); |
| 281 | rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); | 316 | rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); |
| 282 | } | 317 | } |
| 283 | } | 318 | } |
| 284 | void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val){ | 319 | void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) { |
| 285 | if (rgblight_config.enable) { | 320 | if (rgblight_config.enable) { |
| 286 | if (rgblight_config.mode == 1) { | 321 | if (rgblight_config.mode == 1) { |
| 287 | // same static color | 322 | // same static color |
| 288 | rgblight_sethsv_noeeprom(hue, sat, val); | 323 | rgblight_sethsv_noeeprom(hue, sat, val); |
| 289 | } else { | 324 | } else { |
| 290 | // all LEDs in same color | 325 | // all LEDs in same color |
| 291 | if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { | 326 | if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { |
| 292 | // breathing mode, ignore the change of val, use in memory value instead | 327 | // breathing mode, ignore the change of val, use in memory value instead |
| 293 | val = rgblight_config.val; | 328 | val = rgblight_config.val; |
| 294 | } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) { | 329 | } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) { |
| 295 | // rainbow mood and rainbow swirl, ignore the change of hue | 330 | // rainbow mood and rainbow swirl, ignore the change of hue |
| 296 | hue = rgblight_config.hue; | 331 | hue = rgblight_config.hue; |
| 297 | } | 332 | } |
| 298 | } | 333 | } |
| 299 | rgblight_config.hue = hue; | 334 | rgblight_config.hue = hue; |
| 300 | rgblight_config.sat = sat; | 335 | rgblight_config.sat = sat; |
| 301 | rgblight_config.val = val; | 336 | rgblight_config.val = val; |
| 302 | eeconfig_write_rgblight(rgblight_config.raw); | 337 | eeconfig_update_rgblight(rgblight_config.raw); |
| 303 | dprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | 338 | xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); |
| 304 | } | 339 | } |
| 305 | } | 340 | } |
| 306 | 341 | ||
| 307 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b){ | 342 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { |
| 308 | // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b); | 343 | // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b); |
| 309 | for (uint8_t i=0;i<RGBLED_NUM;i++) { | 344 | for (uint8_t i = 0; i < RGBLED_NUM; i++) { |
| 310 | led[i].r = r; | 345 | led[i].r = r; |
| 311 | led[i].g = g; | 346 | led[i].g = g; |
| 312 | led[i].b = b; | 347 | led[i].b = b; |
| 313 | } | 348 | } |
| 314 | rgblight_set(); | 349 | rgblight_set(); |
| 315 | |||
| 316 | } | 350 | } |
| 317 | 351 | ||
| 318 | void rgblight_set(void) { | 352 | void rgblight_set(void) { |
| 319 | if (rgblight_config.enable) { | 353 | if (rgblight_config.enable) { |
| 320 | ws2812_setleds(led, RGBLED_NUM); | 354 | ws2812_setleds(led, RGBLED_NUM); |
| 321 | } else { | 355 | } else { |
| 322 | for (uint8_t i=0;i<RGBLED_NUM;i++) { | 356 | for (uint8_t i = 0; i < RGBLED_NUM; i++) { |
| 323 | led[i].r = 0; | 357 | led[i].r = 0; |
| 324 | led[i].g = 0; | 358 | led[i].g = 0; |
| 325 | led[i].b = 0; | 359 | led[i].b = 0; |
| 326 | } | 360 | } |
| 327 | ws2812_setleds(led, RGBLED_NUM); | 361 | ws2812_setleds(led, RGBLED_NUM); |
| 328 | } | 362 | } |
| 329 | } | 363 | } |
| 330 | 364 | ||
| 365 | #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) | ||
| 366 | |||
| 331 | // Animation timer -- AVR Timer3 | 367 | // Animation timer -- AVR Timer3 |
| 332 | void rgblight_timer_init(void) { | 368 | void rgblight_timer_init(void) { |
| 333 | static uint8_t rgblight_timer_is_init = 0; | 369 | static uint8_t rgblight_timer_is_init = 0; |
| 334 | if (rgblight_timer_is_init) { | 370 | if (rgblight_timer_is_init) { |
| 335 | return; | 371 | return; |
| 336 | } | 372 | } |
| 337 | rgblight_timer_is_init = 1; | 373 | rgblight_timer_is_init = 1; |
| 338 | /* Timer 3 setup */ | 374 | /* Timer 3 setup */ |
| 339 | TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP | 375 | TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP |
| 340 | | _BV(CS30); //Clock selelct: clk/1 | 376 | | _BV(CS30); //Clock selelct: clk/1 |
| 341 | /* Set TOP value */ | 377 | /* Set TOP value */ |
| 342 | uint8_t sreg = SREG; | 378 | uint8_t sreg = SREG; |
| 343 | cli(); | 379 | cli(); |
| 344 | OCR3AH = (RGBLED_TIMER_TOP>>8)&0xff; | 380 | OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff; |
| 345 | OCR3AL = RGBLED_TIMER_TOP&0xff; | 381 | OCR3AL = RGBLED_TIMER_TOP & 0xff; |
| 346 | SREG = sreg; | 382 | SREG = sreg; |
| 347 | } | 383 | } |
| 348 | void rgblight_timer_enable(void) { | 384 | void rgblight_timer_enable(void) { |
| 349 | TIMSK3 |= _BV(OCIE3A); | 385 | TIMSK3 |= _BV(OCIE3A); |
| 350 | dprintf("TIMER3 enabled.\n"); | 386 | dprintf("TIMER3 enabled.\n"); |
| 351 | } | 387 | } |
| 352 | void rgblight_timer_disable(void) { | 388 | void rgblight_timer_disable(void) { |
| 353 | TIMSK3 &= ~_BV(OCIE3A); | 389 | TIMSK3 &= ~_BV(OCIE3A); |
| 354 | dprintf("TIMER3 disabled.\n"); | 390 | dprintf("TIMER3 disabled.\n"); |
| 355 | } | 391 | } |
| 356 | void rgblight_timer_toggle(void) { | 392 | void rgblight_timer_toggle(void) { |
| 357 | TIMSK3 ^= _BV(OCIE3A); | 393 | TIMSK3 ^= _BV(OCIE3A); |
| 358 | dprintf("TIMER3 toggled.\n"); | 394 | dprintf("TIMER3 toggled.\n"); |
| 359 | } | 395 | } |
| 360 | 396 | ||
| 361 | ISR(TIMER3_COMPA_vect) { | 397 | ISR(TIMER3_COMPA_vect) { |
| 362 | // Mode = 1, static light, do nothing here | 398 | // mode = 1, static light, do nothing here |
| 363 | if (rgblight_config.mode>=2 && rgblight_config.mode<=5) { | 399 | if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { |
| 364 | // mode = 2 to 5, breathing mode | 400 | // mode = 2 to 5, breathing mode |
| 365 | rgblight_effect_breathing(rgblight_config.mode-2); | 401 | rgblight_effect_breathing(rgblight_config.mode - 2); |
| 366 | 402 | } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) { | |
| 367 | } else if (rgblight_config.mode>=6 && rgblight_config.mode<=8) { | 403 | // mode = 6 to 8, rainbow mood mod |
| 368 | rgblight_effect_rainbow_mood(rgblight_config.mode-6); | 404 | rgblight_effect_rainbow_mood(rgblight_config.mode - 6); |
| 369 | } else if (rgblight_config.mode>=9 && rgblight_config.mode<=14) { | 405 | } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) { |
| 370 | rgblight_effect_rainbow_swirl(rgblight_config.mode-9); | 406 | // mode = 9 to 14, rainbow swirl mode |
| 371 | } else if (rgblight_config.mode>=15 && rgblight_config.mode<=20) { | 407 | rgblight_effect_rainbow_swirl(rgblight_config.mode - 9); |
| 372 | rgblight_effect_snake(rgblight_config.mode-15); | 408 | } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) { |
| 373 | } else if (rgblight_config.mode>=21 && rgblight_config.mode<=23) { | 409 | // mode = 15 to 20, snake mode |
| 374 | rgblight_effect_knight(rgblight_config.mode-21); | 410 | rgblight_effect_snake(rgblight_config.mode - 15); |
| 375 | } | 411 | } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) { |
| 376 | } | 412 | // mode = 21 to 23, knight mode |
| 377 | 413 | rgblight_effect_knight(rgblight_config.mode - 21); | |
| 378 | // effects | 414 | } |
| 415 | } | ||
| 416 | |||
| 417 | // Effects | ||
| 379 | void rgblight_effect_breathing(uint8_t interval) { | 418 | void rgblight_effect_breathing(uint8_t interval) { |
| 380 | static uint8_t pos = 0; | 419 | static uint8_t pos = 0; |
| 381 | static uint16_t last_timer = 0; | 420 | static uint16_t last_timer = 0; |
| 382 | 421 | ||
| 383 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) return; | 422 | if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) { |
| 384 | last_timer = timer_read(); | 423 | return; |
| 424 | } | ||
| 425 | last_timer = timer_read(); | ||
| 385 | 426 | ||
| 386 | rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos])); | 427 | rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos])); |
| 387 | pos = (pos+1) % 256; | 428 | pos = (pos + 1) % 256; |
| 388 | } | 429 | } |
| 389 | |||
| 390 | void rgblight_effect_rainbow_mood(uint8_t interval) { | 430 | void rgblight_effect_rainbow_mood(uint8_t interval) { |
| 391 | static uint16_t current_hue=0; | 431 | static uint16_t current_hue = 0; |
| 392 | static uint16_t last_timer = 0; | 432 | static uint16_t last_timer = 0; |
| 393 | 433 | ||
| 394 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) return; | 434 | if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) { |
| 395 | last_timer = timer_read(); | 435 | return; |
| 396 | rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val); | 436 | } |
| 397 | current_hue = (current_hue+1) % 360; | 437 | last_timer = timer_read(); |
| 438 | rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val); | ||
| 439 | current_hue = (current_hue + 1) % 360; | ||
| 398 | } | 440 | } |
| 399 | |||
| 400 | void rgblight_effect_rainbow_swirl(uint8_t interval) { | 441 | void rgblight_effect_rainbow_swirl(uint8_t interval) { |
| 401 | static uint16_t current_hue=0; | 442 | static uint16_t current_hue = 0; |
| 402 | static uint16_t last_timer = 0; | 443 | static uint16_t last_timer = 0; |
| 403 | uint16_t hue; | 444 | uint16_t hue; |
| 404 | uint8_t i; | 445 | uint8_t i; |
| 405 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval/2])) return; | 446 | if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval / 2])) { |
| 406 | last_timer = timer_read(); | 447 | return; |
| 407 | for (i=0; i<RGBLED_NUM; i++) { | 448 | } |
| 408 | hue = (360/RGBLED_NUM*i+current_hue)%360; | 449 | last_timer = timer_read(); |
| 409 | sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]); | 450 | for (i = 0; i < RGBLED_NUM; i++) { |
| 410 | } | 451 | hue = (360 / RGBLED_NUM * i + current_hue) % 360; |
| 411 | rgblight_set(); | 452 | sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]); |
| 412 | 453 | } | |
| 413 | if (interval % 2) { | 454 | rgblight_set(); |
| 414 | current_hue = (current_hue+1) % 360; | 455 | |
| 415 | } else { | 456 | if (interval % 2) { |
| 416 | if (current_hue -1 < 0) { | 457 | current_hue = (current_hue + 1) % 360; |
| 417 | current_hue = 359; | 458 | } else { |
| 418 | } else { | 459 | if (current_hue - 1 < 0) { |
| 419 | current_hue = current_hue - 1; | 460 | current_hue = 359; |
| 420 | } | 461 | } else { |
| 421 | 462 | current_hue = current_hue - 1; | |
| 422 | } | 463 | } |
| 464 | } | ||
| 423 | } | 465 | } |
| 424 | void rgblight_effect_snake(uint8_t interval) { | 466 | void rgblight_effect_snake(uint8_t interval) { |
| 425 | static uint8_t pos=0; | 467 | static uint8_t pos = 0; |
| 426 | static uint16_t last_timer = 0; | 468 | static uint16_t last_timer = 0; |
| 427 | uint8_t i,j; | 469 | uint8_t i, j; |
| 428 | int8_t k; | 470 | int8_t k; |
| 429 | int8_t increament = 1; | 471 | int8_t increment = 1; |
| 430 | if (interval%2) increament = -1; | 472 | if (interval % 2) { |
| 431 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval/2])) return; | 473 | increment = -1; |
| 432 | last_timer = timer_read(); | 474 | } |
| 433 | for (i=0;i<RGBLED_NUM;i++) { | 475 | if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval / 2])) { |
| 434 | led[i].r=0; | 476 | return; |
| 435 | led[i].g=0; | 477 | } |
| 436 | led[i].b=0; | 478 | last_timer = timer_read(); |
| 437 | for (j=0;j<RGBLIGHT_EFFECT_SNAKE_LENGTH;j++) { | 479 | for (i = 0; i < RGBLED_NUM; i++) { |
| 438 | k = pos+j*increament; | 480 | led[i].r = 0; |
| 439 | if (k<0) k = k+RGBLED_NUM; | 481 | led[i].g = 0; |
| 440 | if (i==k) { | 482 | led[i].b = 0; |
| 441 | sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]); | 483 | for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) { |
| 442 | } | 484 | k = pos + j * increment; |
| 443 | } | 485 | if (k < 0) { |
| 444 | } | 486 | k = k + RGBLED_NUM; |
| 445 | rgblight_set(); | 487 | } |
| 446 | if (increament == 1) { | 488 | if (i == k) { |
| 447 | if (pos - 1 < 0) { | 489 | sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]); |
| 448 | pos = RGBLED_NUM-1; | 490 | } |
| 449 | } else { | 491 | } |
| 450 | pos -= 1; | 492 | } |
| 451 | } | 493 | rgblight_set(); |
| 452 | } else { | 494 | if (increment == 1) { |
| 453 | pos = (pos+1)%RGBLED_NUM; | 495 | if (pos - 1 < 0) { |
| 454 | } | 496 | pos = RGBLED_NUM - 1; |
| 455 | 497 | } else { | |
| 498 | pos -= 1; | ||
| 499 | } | ||
| 500 | } else { | ||
| 501 | pos = (pos + 1) % RGBLED_NUM; | ||
| 502 | } | ||
| 456 | } | 503 | } |
| 457 | |||
| 458 | void rgblight_effect_knight(uint8_t interval) { | 504 | void rgblight_effect_knight(uint8_t interval) { |
| 459 | static int8_t pos=0; | 505 | static int8_t pos = 0; |
| 460 | static uint16_t last_timer = 0; | 506 | static uint16_t last_timer = 0; |
| 461 | uint8_t i,j,cur; | 507 | uint8_t i, j, cur; |
| 462 | int8_t k; | 508 | int8_t k; |
| 463 | struct cRGB preled[RGBLED_NUM]; | 509 | struct cRGB preled[RGBLED_NUM]; |
| 464 | static int8_t increament = -1; | 510 | static int8_t increment = -1; |
| 465 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) return; | 511 | if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) { |
| 466 | last_timer = timer_read(); | 512 | return; |
| 467 | for (i=0;i<RGBLED_NUM;i++) { | 513 | } |
| 468 | preled[i].r=0; | 514 | last_timer = timer_read(); |
| 469 | preled[i].g=0; | 515 | for (i = 0; i < RGBLED_NUM; i++) { |
| 470 | preled[i].b=0; | 516 | preled[i].r = 0; |
| 471 | for (j=0;j<RGBLIGHT_EFFECT_KNIGHT_LENGTH;j++) { | 517 | preled[i].g = 0; |
| 472 | k = pos+j*increament; | 518 | preled[i].b = 0; |
| 473 | if (k<0) k = 0; | 519 | for (j = 0; j < RGBLIGHT_EFFECT_KNIGHT_LENGTH; j++) { |
| 474 | if (k>=RGBLED_NUM) k=RGBLED_NUM-1; | 520 | k = pos + j * increment; |
| 475 | if (i==k) { | 521 | if (k < 0) { |
| 476 | sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); | 522 | k = 0; |
| 477 | } | 523 | } |
| 478 | } | 524 | if (k >= RGBLED_NUM) { |
| 479 | } | 525 | k = RGBLED_NUM - 1; |
| 480 | if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) { | 526 | } |
| 481 | for (i=0;i<RGBLED_NUM;i++) { | 527 | if (i == k) { |
| 482 | cur = (i+RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM; | 528 | sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); |
| 483 | led[i].r = preled[cur].r; | 529 | } |
| 484 | led[i].g = preled[cur].g; | 530 | } |
| 485 | led[i].b = preled[cur].b; | 531 | } |
| 486 | } | 532 | if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) { |
| 487 | } | 533 | for (i = 0; i < RGBLED_NUM; i++) { |
| 488 | rgblight_set(); | 534 | cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM; |
| 489 | if (increament == 1) { | 535 | led[i].r = preled[cur].r; |
| 490 | if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) { | 536 | led[i].g = preled[cur].g; |
| 491 | pos = 0- RGBLIGHT_EFFECT_KNIGHT_LENGTH; | 537 | led[i].b = preled[cur].b; |
| 492 | increament = -1; | 538 | } |
| 493 | } else { | 539 | } |
| 494 | pos -= 1; | 540 | rgblight_set(); |
| 495 | } | 541 | if (increment == 1) { |
| 496 | } else { | 542 | if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) { |
| 497 | if (pos+1>RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH) { | 543 | pos = 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH; |
| 498 | pos = RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH-1; | 544 | increment = -1; |
| 499 | increament = 1; | 545 | } else { |
| 500 | } else { | 546 | pos -= 1; |
| 501 | pos += 1; | 547 | } |
| 502 | } | 548 | } else { |
| 503 | } | 549 | if (pos + 1 > RGBLED_NUM + RGBLIGHT_EFFECT_KNIGHT_LENGTH) { |
| 504 | 550 | pos = RGBLED_NUM + RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; | |
| 551 | increment = 1; | ||
| 552 | } else { | ||
| 553 | pos += 1; | ||
| 554 | } | ||
| 555 | } | ||
| 505 | } | 556 | } |
| 557 | |||
| 558 | #endif | ||
diff --git a/quantum/rgblight.h b/quantum/rgblight.h index 9e1562328..17f04ffcf 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h | |||
| @@ -1,8 +1,11 @@ | |||
| 1 | #ifndef RGBLIGHT_H | 1 | #ifndef RGBLIGHT_H |
| 2 | #define RGBLIGHT_H | 2 | #define RGBLIGHT_H |
| 3 | 3 | ||
| 4 | #ifndef RGBLIGHT_MODES | 4 | |
| 5 | #define RGBLIGHT_MODES 23 | 5 | #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) |
| 6 | #define RGBLIGHT_MODES 23 | ||
| 7 | #else | ||
| 8 | #define RGBLIGHT_MODES 1 | ||
| 6 | #endif | 9 | #endif |
| 7 | 10 | ||
| 8 | #ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH | 11 | #ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH |
| @@ -37,6 +40,12 @@ | |||
| 37 | #include "eeconfig.h" | 40 | #include "eeconfig.h" |
| 38 | #include "light_ws2812.h" | 41 | #include "light_ws2812.h" |
| 39 | 42 | ||
| 43 | extern const uint8_t RGBLED_BREATHING_INTERVALS[4] PROGMEM; | ||
| 44 | extern const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[3] PROGMEM; | ||
| 45 | extern const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[3] PROGMEM; | ||
| 46 | extern const uint8_t RGBLED_SNAKE_INTERVALS[3] PROGMEM; | ||
| 47 | extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM; | ||
| 48 | |||
| 40 | typedef union { | 49 | typedef union { |
| 41 | uint32_t raw; | 50 | uint32_t raw; |
| 42 | struct { | 51 | struct { |
| @@ -64,10 +73,9 @@ void rgblight_decrease_val(void); | |||
| 64 | void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val); | 73 | 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); | 74 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b); |
| 66 | 75 | ||
| 67 | #define EECONFIG_RGBLIGHT (uint8_t *)7 | ||
| 68 | uint32_t eeconfig_read_rgblight(void); | 76 | uint32_t eeconfig_read_rgblight(void); |
| 69 | void eeconfig_write_rgblight(uint32_t val); | 77 | void eeconfig_update_rgblight(uint32_t val); |
| 70 | void eeconfig_write_rgblight_default(void); | 78 | void eeconfig_update_rgblight_default(void); |
| 71 | void eeconfig_debug_rgblight(void); | 79 | void eeconfig_debug_rgblight(void); |
| 72 | 80 | ||
| 73 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); | 81 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); |
diff --git a/quantum/serial_link/LICENSE b/quantum/serial_link/LICENSE new file mode 100644 index 000000000..d7cc3198c --- /dev/null +++ b/quantum/serial_link/LICENSE | |||
| @@ -0,0 +1,21 @@ | |||
| 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..2c87d64c2 --- /dev/null +++ b/quantum/serial_link/protocol/byte_stuffer.c | |||
| @@ -0,0 +1,142 @@ | |||
| 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 | typedef struct byte_stuffer_state { | ||
| 35 | uint16_t next_zero; | ||
| 36 | uint16_t data_pos; | ||
| 37 | bool long_frame; | ||
| 38 | uint8_t data[MAX_FRAME_SIZE]; | ||
| 39 | }byte_stuffer_state_t; | ||
| 40 | |||
| 41 | static byte_stuffer_state_t states[NUM_LINKS]; | ||
| 42 | |||
| 43 | void init_byte_stuffer_state(byte_stuffer_state_t* state) { | ||
| 44 | state->next_zero = 0; | ||
| 45 | state->data_pos = 0; | ||
| 46 | state->long_frame = false; | ||
| 47 | } | ||
| 48 | |||
| 49 | void init_byte_stuffer(void) { | ||
| 50 | int i; | ||
| 51 | for (i=0;i<NUM_LINKS;i++) { | ||
| 52 | init_byte_stuffer_state(&states[i]); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data) { | ||
| 57 | byte_stuffer_state_t* state = &states[link]; | ||
| 58 | // Start of a new frame | ||
| 59 | if (state->next_zero == 0) { | ||
| 60 | state->next_zero = data; | ||
| 61 | state->long_frame = data == 0xFF; | ||
| 62 | state->data_pos = 0; | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | |||
| 66 | state->next_zero--; | ||
| 67 | if (data == 0) { | ||
| 68 | if (state->next_zero == 0) { | ||
| 69 | // The frame is completed | ||
| 70 | if (state->data_pos > 0) { | ||
| 71 | validator_recv_frame(link, state->data, state->data_pos); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | else { | ||
| 75 | // The frame is invalid, so reset | ||
| 76 | init_byte_stuffer_state(state); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | else { | ||
| 80 | if (state->data_pos == MAX_FRAME_SIZE) { | ||
| 81 | // We exceeded our maximum frame size | ||
| 82 | // therefore there's nothing else to do than reset to a new frame | ||
| 83 | state->next_zero = data; | ||
| 84 | state->long_frame = data == 0xFF; | ||
| 85 | state->data_pos = 0; | ||
| 86 | } | ||
| 87 | else if (state->next_zero == 0) { | ||
| 88 | if (state->long_frame) { | ||
| 89 | // This is part of a long frame, so continue | ||
| 90 | state->next_zero = data; | ||
| 91 | state->long_frame = data == 0xFF; | ||
| 92 | } | ||
| 93 | else { | ||
| 94 | // Special case for zeroes | ||
| 95 | state->next_zero = data; | ||
| 96 | state->data[state->data_pos++] = 0; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | else { | ||
| 100 | state->data[state->data_pos++] = data; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) { | ||
| 106 | send_data(link, &num_non_zero, 1); | ||
| 107 | if (end > start) { | ||
| 108 | send_data(link, start, end-start); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 113 | const uint8_t zero = 0; | ||
| 114 | if (size > 0) { | ||
| 115 | uint16_t num_non_zero = 1; | ||
| 116 | uint8_t* end = data + size; | ||
| 117 | uint8_t* start = data; | ||
| 118 | while (data < end) { | ||
| 119 | if (num_non_zero == 0xFF) { | ||
| 120 | // There's more data after big non-zero block | ||
| 121 | // So send it, and start a new block | ||
| 122 | send_block(link, start, data, num_non_zero); | ||
| 123 | start = data; | ||
| 124 | num_non_zero = 1; | ||
| 125 | } | ||
| 126 | else { | ||
| 127 | if (*data == 0) { | ||
| 128 | // A zero encountered, so send the block | ||
| 129 | send_block(link, start, data, num_non_zero); | ||
| 130 | start = data + 1; | ||
| 131 | num_non_zero = 1; | ||
| 132 | } | ||
| 133 | else { | ||
| 134 | num_non_zero++; | ||
| 135 | } | ||
| 136 | ++data; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | send_block(link, start, data, num_non_zero); | ||
| 140 | send_data(link, &zero, 1); | ||
| 141 | } | ||
| 142 | } | ||
diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h new file mode 100644 index 000000000..97e896856 --- /dev/null +++ b/quantum/serial_link/protocol/byte_stuffer.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 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 | #define MAX_FRAME_SIZE 1024 | ||
| 31 | #define NUM_LINKS 2 | ||
| 32 | |||
| 33 | void init_byte_stuffer(void); | ||
| 34 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data); | ||
| 35 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
| 36 | |||
| 37 | #endif | ||
diff --git a/quantum/serial_link/protocol/frame_router.c b/quantum/serial_link/protocol/frame_router.c new file mode 100644 index 000000000..04b8c2e75 --- /dev/null +++ b/quantum/serial_link/protocol/frame_router.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* | ||
| 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..ff795fe20 --- /dev/null +++ b/quantum/serial_link/protocol/transport.c | |||
| @@ -0,0 +1,128 @@ | |||
| 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 reinitialize_serial_link_transport(void) { | ||
| 35 | num_remote_objects = 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) { | ||
| 39 | unsigned int i; | ||
| 40 | for(i=0;i<_num_remote_objects;i++) { | ||
| 41 | remote_object_t* obj = _remote_objects[i]; | ||
| 42 | remote_objects[num_remote_objects++] = obj; | ||
| 43 | if (obj->object_type == MASTER_TO_ALL_SLAVES) { | ||
| 44 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; | ||
| 45 | triple_buffer_init(tb); | ||
| 46 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 47 | tb = (triple_buffer_object_t*)start; | ||
| 48 | triple_buffer_init(tb); | ||
| 49 | } | ||
| 50 | else if(obj->object_type == MASTER_TO_SINGLE_SLAVE) { | ||
| 51 | uint8_t* start = obj->buffer; | ||
| 52 | unsigned int j; | ||
| 53 | for (j=0;j<NUM_SLAVES;j++) { | ||
| 54 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 55 | triple_buffer_init(tb); | ||
| 56 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 57 | } | ||
| 58 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 59 | triple_buffer_init(tb); | ||
| 60 | } | ||
| 61 | else { | ||
| 62 | uint8_t* start = obj->buffer; | ||
| 63 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 64 | triple_buffer_init(tb); | ||
| 65 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 66 | unsigned int j; | ||
| 67 | for (j=0;j<NUM_SLAVES;j++) { | ||
| 68 | tb = (triple_buffer_object_t*)start; | ||
| 69 | triple_buffer_init(tb); | ||
| 70 | start += REMOTE_OBJECT_SIZE(obj->object_size); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
| 77 | uint8_t id = data[size-1]; | ||
| 78 | if (id < num_remote_objects) { | ||
| 79 | remote_object_t* obj = remote_objects[id]; | ||
| 80 | if (obj->object_size == size - 1) { | ||
| 81 | uint8_t* start; | ||
| 82 | if (obj->object_type == MASTER_TO_ALL_SLAVES) { | ||
| 83 | start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 84 | } | ||
| 85 | else if(obj->object_type == SLAVE_TO_MASTER) { | ||
| 86 | start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 87 | start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size); | ||
| 88 | } | ||
| 89 | else { | ||
| 90 | start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 91 | } | ||
| 92 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 93 | void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb); | ||
| 94 | memcpy(ptr, data, size - 1); | ||
| 95 | triple_buffer_end_write_internal(tb); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | void update_transport(void) { | ||
| 101 | unsigned int i; | ||
| 102 | for(i=0;i<num_remote_objects;i++) { | ||
| 103 | remote_object_t* obj = remote_objects[i]; | ||
| 104 | if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) { | ||
| 105 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; | ||
| 106 | uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); | ||
| 107 | if (ptr) { | ||
| 108 | ptr[obj->object_size] = i; | ||
| 109 | uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0; | ||
| 110 | router_send_frame(dest, ptr, obj->object_size + 1); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | else { | ||
| 114 | uint8_t* start = obj->buffer; | ||
| 115 | unsigned int j; | ||
| 116 | for (j=0;j<NUM_SLAVES;j++) { | ||
| 117 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 118 | uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); | ||
| 119 | if (ptr) { | ||
| 120 | ptr[obj->object_size] = i; | ||
| 121 | uint8_t dest = j + 1; | ||
| 122 | router_send_frame(dest, ptr, obj->object_size + 1); | ||
| 123 | } | ||
| 124 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h new file mode 100644 index 000000000..2c5d890b2 --- /dev/null +++ b/quantum/serial_link/protocol/transport.h | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | /* | ||
| 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 (type*)triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 86 | } | ||
| 87 | |||
| 88 | #define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \ | ||
| 89 | REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \ | ||
| 90 | remote_object_##name##_t remote_object_##name = { \ | ||
| 91 | .object = { \ | ||
| 92 | .object_type = MASTER_TO_SINGLE_SLAVE, \ | ||
| 93 | .object_size = sizeof(type), \ | ||
| 94 | } \ | ||
| 95 | }; \ | ||
| 96 | type* begin_write_##name(uint8_t slave) { \ | ||
| 97 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 98 | uint8_t* start = obj->buffer;\ | ||
| 99 | start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 100 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 101 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 102 | }\ | ||
| 103 | void end_write_##name(uint8_t slave) { \ | ||
| 104 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 105 | uint8_t* start = obj->buffer;\ | ||
| 106 | start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 107 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 108 | triple_buffer_end_write_internal(tb); \ | ||
| 109 | signal_data_written(); \ | ||
| 110 | }\ | ||
| 111 | type* read_##name() { \ | ||
| 112 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 113 | uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\ | ||
| 114 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 115 | return (type*)triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 116 | } | ||
| 117 | |||
| 118 | #define SLAVE_TO_MASTER_OBJECT(name, type) \ | ||
| 119 | REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \ | ||
| 120 | remote_object_##name##_t remote_object_##name = { \ | ||
| 121 | .object = { \ | ||
| 122 | .object_type = SLAVE_TO_MASTER, \ | ||
| 123 | .object_size = sizeof(type), \ | ||
| 124 | } \ | ||
| 125 | }; \ | ||
| 126 | type* begin_write_##name(void) { \ | ||
| 127 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 128 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 129 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 130 | }\ | ||
| 131 | void end_write_##name(void) { \ | ||
| 132 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 133 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 134 | triple_buffer_end_write_internal(tb); \ | ||
| 135 | signal_data_written(); \ | ||
| 136 | }\ | ||
| 137 | type* read_##name(uint8_t slave) { \ | ||
| 138 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 139 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ | ||
| 140 | start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \ | ||
| 141 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 142 | return (type*)triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 143 | } | ||
| 144 | |||
| 145 | #define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name | ||
| 146 | |||
| 147 | void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); | ||
| 148 | void reinitialize_serial_link_transport(void); | ||
| 149 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); | ||
| 150 | void update_transport(void); | ||
| 151 | |||
| 152 | #endif | ||
diff --git a/quantum/serial_link/protocol/triple_buffered_object.c b/quantum/serial_link/protocol/triple_buffered_object.c new file mode 100644 index 000000000..e3e8989d3 --- /dev/null +++ b/quantum/serial_link/protocol/triple_buffered_object.c | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 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.cpp b/quantum/serial_link/tests/byte_stuffer_tests.cpp new file mode 100644 index 000000000..ff49d727b --- /dev/null +++ b/quantum/serial_link/tests/byte_stuffer_tests.cpp | |||
| @@ -0,0 +1,483 @@ | |||
| 1 | /* | ||
| 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 "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | #include <vector> | ||
| 28 | #include <algorithm> | ||
| 29 | extern "C" { | ||
| 30 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 31 | #include "serial_link/protocol/frame_validator.h" | ||
| 32 | #include "serial_link/protocol/physical.h" | ||
| 33 | } | ||
| 34 | |||
| 35 | using testing::_; | ||
| 36 | using testing::ElementsAreArray; | ||
| 37 | using testing::Args; | ||
| 38 | |||
| 39 | class ByteStuffer : public ::testing::Test{ | ||
| 40 | public: | ||
| 41 | ByteStuffer() { | ||
| 42 | Instance = this; | ||
| 43 | init_byte_stuffer(); | ||
| 44 | } | ||
| 45 | |||
| 46 | ~ByteStuffer() { | ||
| 47 | Instance = nullptr; | ||
| 48 | } | ||
| 49 | |||
| 50 | MOCK_METHOD3(validator_recv_frame, void (uint8_t link, uint8_t* data, uint16_t size)); | ||
| 51 | |||
| 52 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 53 | std::copy(data, data + size, std::back_inserter(sent_data)); | ||
| 54 | } | ||
| 55 | std::vector<uint8_t> sent_data; | ||
| 56 | |||
| 57 | static ByteStuffer* Instance; | ||
| 58 | }; | ||
| 59 | |||
| 60 | ByteStuffer* ByteStuffer::Instance = nullptr; | ||
| 61 | |||
| 62 | extern "C" { | ||
| 63 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 64 | ByteStuffer::Instance->validator_recv_frame(link, data, size); | ||
| 65 | } | ||
| 66 | |||
| 67 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 68 | ByteStuffer::Instance->send_data(link, data, size); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { | ||
| 73 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 74 | .Times(0); | ||
| 75 | byte_stuffer_recv_byte(0, 0); | ||
| 76 | } | ||
| 77 | |||
| 78 | TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { | ||
| 79 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 80 | .Times(0); | ||
| 81 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 82 | } | ||
| 83 | |||
| 84 | TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) { | ||
| 85 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 86 | .Times(0); | ||
| 87 | byte_stuffer_recv_byte(0, 0x4A); | ||
| 88 | } | ||
| 89 | |||
| 90 | TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) { | ||
| 91 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 92 | .Times(0); | ||
| 93 | byte_stuffer_recv_byte(0, 1); | ||
| 94 | byte_stuffer_recv_byte(0, 0); | ||
| 95 | } | ||
| 96 | |||
| 97 | TEST_F(ByteStuffer, receives_single_byte_valid_frame) { | ||
| 98 | uint8_t expected[] = {0x37}; | ||
| 99 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 100 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 101 | byte_stuffer_recv_byte(0, 2); | ||
| 102 | byte_stuffer_recv_byte(0, 0x37); | ||
| 103 | byte_stuffer_recv_byte(0, 0); | ||
| 104 | } | ||
| 105 | TEST_F(ByteStuffer, receives_three_bytes_valid_frame) { | ||
| 106 | uint8_t expected[] = {0x37, 0x99, 0xFF}; | ||
| 107 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 108 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 109 | byte_stuffer_recv_byte(0, 4); | ||
| 110 | byte_stuffer_recv_byte(0, 0x37); | ||
| 111 | byte_stuffer_recv_byte(0, 0x99); | ||
| 112 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 113 | byte_stuffer_recv_byte(0, 0); | ||
| 114 | } | ||
| 115 | |||
| 116 | TEST_F(ByteStuffer, receives_single_zero_valid_frame) { | ||
| 117 | uint8_t expected[] = {0}; | ||
| 118 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 119 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 120 | byte_stuffer_recv_byte(0, 1); | ||
| 121 | byte_stuffer_recv_byte(0, 1); | ||
| 122 | byte_stuffer_recv_byte(0, 0); | ||
| 123 | } | ||
| 124 | |||
| 125 | TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) { | ||
| 126 | uint8_t expected[] = {5, 0, 3, 0}; | ||
| 127 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 128 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 129 | byte_stuffer_recv_byte(0, 2); | ||
| 130 | byte_stuffer_recv_byte(0, 5); | ||
| 131 | byte_stuffer_recv_byte(0, 2); | ||
| 132 | byte_stuffer_recv_byte(0, 3); | ||
| 133 | byte_stuffer_recv_byte(0, 1); | ||
| 134 | byte_stuffer_recv_byte(0, 0); | ||
| 135 | } | ||
| 136 | |||
| 137 | |||
| 138 | TEST_F(ByteStuffer, receives_two_valid_frames) { | ||
| 139 | uint8_t expected1[] = {5, 0}; | ||
| 140 | uint8_t expected2[] = {3}; | ||
| 141 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 142 | .With(Args<1, 2>(ElementsAreArray(expected1))); | ||
| 143 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 144 | .With(Args<1, 2>(ElementsAreArray(expected2))); | ||
| 145 | byte_stuffer_recv_byte(1, 2); | ||
| 146 | byte_stuffer_recv_byte(1, 5); | ||
| 147 | byte_stuffer_recv_byte(1, 1); | ||
| 148 | byte_stuffer_recv_byte(1, 0); | ||
| 149 | byte_stuffer_recv_byte(1, 2); | ||
| 150 | byte_stuffer_recv_byte(1, 3); | ||
| 151 | byte_stuffer_recv_byte(1, 0); | ||
| 152 | } | ||
| 153 | |||
| 154 | TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) { | ||
| 155 | uint8_t expected[] = {5, 7}; | ||
| 156 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 157 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 158 | byte_stuffer_recv_byte(1, 3); | ||
| 159 | byte_stuffer_recv_byte(1, 1); | ||
| 160 | byte_stuffer_recv_byte(1, 0); | ||
| 161 | byte_stuffer_recv_byte(1, 3); | ||
| 162 | byte_stuffer_recv_byte(1, 5); | ||
| 163 | byte_stuffer_recv_byte(1, 7); | ||
| 164 | byte_stuffer_recv_byte(1, 0); | ||
| 165 | } | ||
| 166 | |||
| 167 | TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { | ||
| 168 | uint8_t expected[] = {5, 7}; | ||
| 169 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 170 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 171 | byte_stuffer_recv_byte(0, 2); | ||
| 172 | byte_stuffer_recv_byte(0, 9); | ||
| 173 | byte_stuffer_recv_byte(0, 4); // This should have been zero | ||
| 174 | byte_stuffer_recv_byte(0, 0); | ||
| 175 | byte_stuffer_recv_byte(0, 3); | ||
| 176 | byte_stuffer_recv_byte(0, 5); | ||
| 177 | byte_stuffer_recv_byte(0, 7); | ||
| 178 | byte_stuffer_recv_byte(0, 0); | ||
| 179 | } | ||
| 180 | |||
| 181 | TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) { | ||
| 182 | uint8_t expected[254]; | ||
| 183 | int i; | ||
| 184 | for (i=0;i<254;i++) { | ||
| 185 | expected[i] = i + 1; | ||
| 186 | } | ||
| 187 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 188 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 189 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 190 | for (i=0;i<254;i++) { | ||
| 191 | byte_stuffer_recv_byte(0, i+1); | ||
| 192 | } | ||
| 193 | byte_stuffer_recv_byte(0, 0); | ||
| 194 | } | ||
| 195 | |||
| 196 | TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) { | ||
| 197 | uint8_t expected[255]; | ||
| 198 | int i; | ||
| 199 | for (i=0;i<254;i++) { | ||
| 200 | expected[i] = i + 1; | ||
| 201 | } | ||
| 202 | expected[254] = 7; | ||
| 203 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 204 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 205 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 206 | for (i=0;i<254;i++) { | ||
| 207 | byte_stuffer_recv_byte(0, i+1); | ||
| 208 | } | ||
| 209 | byte_stuffer_recv_byte(0, 2); | ||
| 210 | byte_stuffer_recv_byte(0, 7); | ||
| 211 | byte_stuffer_recv_byte(0, 0); | ||
| 212 | } | ||
| 213 | |||
| 214 | TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) { | ||
| 215 | uint8_t expected[255]; | ||
| 216 | int i; | ||
| 217 | for (i=0;i<254;i++) { | ||
| 218 | expected[i] = i + 1; | ||
| 219 | } | ||
| 220 | expected[254] = 0; | ||
| 221 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 222 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 223 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 224 | for (i=0;i<254;i++) { | ||
| 225 | byte_stuffer_recv_byte(0, i+1); | ||
| 226 | } | ||
| 227 | byte_stuffer_recv_byte(0, 1); | ||
| 228 | byte_stuffer_recv_byte(0, 1); | ||
| 229 | byte_stuffer_recv_byte(0, 0); | ||
| 230 | } | ||
| 231 | |||
| 232 | TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) { | ||
| 233 | uint8_t expected[515]; | ||
| 234 | int i; | ||
| 235 | int j; | ||
| 236 | for (j=0;j<2;j++) { | ||
| 237 | for (i=0;i<254;i++) { | ||
| 238 | expected[i+254*j] = i + 1; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | for (i=0;i<7;i++) { | ||
| 242 | expected[254*2+i] = i + 1; | ||
| 243 | } | ||
| 244 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 245 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 246 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 247 | for (i=0;i<254;i++) { | ||
| 248 | byte_stuffer_recv_byte(0, i+1); | ||
| 249 | } | ||
| 250 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 251 | for (i=0;i<254;i++) { | ||
| 252 | byte_stuffer_recv_byte(0, i+1); | ||
| 253 | } | ||
| 254 | byte_stuffer_recv_byte(0, 8); | ||
| 255 | byte_stuffer_recv_byte(0, 1); | ||
| 256 | byte_stuffer_recv_byte(0, 2); | ||
| 257 | byte_stuffer_recv_byte(0, 3); | ||
| 258 | byte_stuffer_recv_byte(0, 4); | ||
| 259 | byte_stuffer_recv_byte(0, 5); | ||
| 260 | byte_stuffer_recv_byte(0, 6); | ||
| 261 | byte_stuffer_recv_byte(0, 7); | ||
| 262 | byte_stuffer_recv_byte(0, 0); | ||
| 263 | } | ||
| 264 | |||
| 265 | TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { | ||
| 266 | uint8_t expected[MAX_FRAME_SIZE] = {}; | ||
| 267 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 268 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 269 | int i; | ||
| 270 | byte_stuffer_recv_byte(0, 1); | ||
| 271 | for(i=0;i<MAX_FRAME_SIZE;i++) { | ||
| 272 | byte_stuffer_recv_byte(0, 1); | ||
| 273 | } | ||
| 274 | byte_stuffer_recv_byte(0, 0); | ||
| 275 | } | ||
| 276 | |||
| 277 | TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { | ||
| 278 | uint8_t expected[1] = {0}; | ||
| 279 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 280 | .Times(0); | ||
| 281 | int i; | ||
| 282 | byte_stuffer_recv_byte(0, 1); | ||
| 283 | for(i=0;i<MAX_FRAME_SIZE;i++) { | ||
| 284 | byte_stuffer_recv_byte(0, 1); | ||
| 285 | } | ||
| 286 | byte_stuffer_recv_byte(0, 1); | ||
| 287 | byte_stuffer_recv_byte(0, 0); | ||
| 288 | } | ||
| 289 | |||
| 290 | TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) { | ||
| 291 | uint8_t expected[1] = {1}; | ||
| 292 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 293 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 294 | int i; | ||
| 295 | byte_stuffer_recv_byte(0, 1); | ||
| 296 | for(i=0;i<MAX_FRAME_SIZE;i++) { | ||
| 297 | byte_stuffer_recv_byte(0, 1); | ||
| 298 | } | ||
| 299 | byte_stuffer_recv_byte(0, 2); | ||
| 300 | byte_stuffer_recv_byte(0, 1); | ||
| 301 | byte_stuffer_recv_byte(0, 0); | ||
| 302 | } | ||
| 303 | |||
| 304 | TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) { | ||
| 305 | EXPECT_EQ(sent_data.size(), 0); | ||
| 306 | byte_stuffer_send_frame(0, NULL, 0); | ||
| 307 | } | ||
| 308 | |||
| 309 | TEST_F(ByteStuffer, send_one_byte_frame) { | ||
| 310 | uint8_t data[] = {5}; | ||
| 311 | byte_stuffer_send_frame(1, data, 1); | ||
| 312 | uint8_t expected[] = {2, 5, 0}; | ||
| 313 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 314 | } | ||
| 315 | |||
| 316 | TEST_F(ByteStuffer, sends_two_byte_frame) { | ||
| 317 | uint8_t data[] = {5, 0x77}; | ||
| 318 | byte_stuffer_send_frame(0, data, 2); | ||
| 319 | uint8_t expected[] = {3, 5, 0x77, 0}; | ||
| 320 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 321 | } | ||
| 322 | |||
| 323 | TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) { | ||
| 324 | uint8_t data[] = {0}; | ||
| 325 | byte_stuffer_send_frame(0, data, 1); | ||
| 326 | uint8_t expected[] = {1, 1, 0}; | ||
| 327 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 328 | } | ||
| 329 | |||
| 330 | TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) { | ||
| 331 | uint8_t data[] = {0, 9}; | ||
| 332 | byte_stuffer_send_frame(1, data, 2); | ||
| 333 | uint8_t expected[] = {1, 2, 9, 0}; | ||
| 334 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 335 | } | ||
| 336 | |||
| 337 | TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) { | ||
| 338 | uint8_t data[] = {9, 0}; | ||
| 339 | byte_stuffer_send_frame(1, data, 2); | ||
| 340 | uint8_t expected[] = {2, 9, 1, 0}; | ||
| 341 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 342 | } | ||
| 343 | |||
| 344 | TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) { | ||
| 345 | uint8_t data[] = {9, 0, 0x68}; | ||
| 346 | byte_stuffer_send_frame(0, data, 3); | ||
| 347 | uint8_t expected[] = {2, 9, 2, 0x68, 0}; | ||
| 348 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 349 | } | ||
| 350 | |||
| 351 | TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) { | ||
| 352 | uint8_t data[] = {0, 0x55, 0}; | ||
| 353 | byte_stuffer_send_frame(0, data, 3); | ||
| 354 | uint8_t expected[] = {1, 2, 0x55, 1, 0}; | ||
| 355 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 356 | } | ||
| 357 | |||
| 358 | TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) { | ||
| 359 | uint8_t data[] = {0, 0, 0}; | ||
| 360 | byte_stuffer_send_frame(0, data, 3); | ||
| 361 | uint8_t expected[] = {1, 1, 1, 1, 0}; | ||
| 362 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 363 | } | ||
| 364 | |||
| 365 | TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) { | ||
| 366 | uint8_t data[254]; | ||
| 367 | int i; | ||
| 368 | for(i=0;i<254;i++) { | ||
| 369 | data[i] = i + 1; | ||
| 370 | } | ||
| 371 | byte_stuffer_send_frame(0, data, 254); | ||
| 372 | uint8_t expected[256]; | ||
| 373 | expected[0] = 0xFF; | ||
| 374 | for(i=1;i<255;i++) { | ||
| 375 | expected[i] = i; | ||
| 376 | } | ||
| 377 | expected[255] = 0; | ||
| 378 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 379 | } | ||
| 380 | |||
| 381 | TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) { | ||
| 382 | uint8_t data[255]; | ||
| 383 | int i; | ||
| 384 | for(i=0;i<255;i++) { | ||
| 385 | data[i] = i + 1; | ||
| 386 | } | ||
| 387 | byte_stuffer_send_frame(0, data, 255); | ||
| 388 | uint8_t expected[258]; | ||
| 389 | expected[0] = 0xFF; | ||
| 390 | for(i=1;i<255;i++) { | ||
| 391 | expected[i] = i; | ||
| 392 | } | ||
| 393 | expected[255] = 2; | ||
| 394 | expected[256] = 255; | ||
| 395 | expected[257] = 0; | ||
| 396 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 397 | } | ||
| 398 | |||
| 399 | TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { | ||
| 400 | uint8_t data[255]; | ||
| 401 | int i; | ||
| 402 | for(i=0;i<254;i++) { | ||
| 403 | data[i] = i + 1; | ||
| 404 | } | ||
| 405 | data[254] = 0; | ||
| 406 | byte_stuffer_send_frame(0, data, 255); | ||
| 407 | uint8_t expected[258]; | ||
| 408 | expected[0] = 0xFF; | ||
| 409 | for(i=1;i<255;i++) { | ||
| 410 | expected[i] = i; | ||
| 411 | } | ||
| 412 | expected[255] = 1; | ||
| 413 | expected[256] = 1; | ||
| 414 | expected[257] = 0; | ||
| 415 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 416 | } | ||
| 417 | |||
| 418 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) { | ||
| 419 | uint8_t original_data[] = { 1, 2, 3}; | ||
| 420 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 421 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 422 | .With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 423 | int i; | ||
| 424 | for(auto& d : sent_data) { | ||
| 425 | byte_stuffer_recv_byte(1, d); | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) { | ||
| 430 | uint8_t original_data[] = { 1, 0, 3, 0, 0, 9}; | ||
| 431 | byte_stuffer_send_frame(1, original_data, sizeof(original_data)); | ||
| 432 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 433 | .With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 434 | int i; | ||
| 435 | for(auto& d : sent_data) { | ||
| 436 | byte_stuffer_recv_byte(1, d); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) { | ||
| 441 | uint8_t original_data[254]; | ||
| 442 | int i; | ||
| 443 | for(i=0;i<254;i++) { | ||
| 444 | original_data[i] = i + 1; | ||
| 445 | } | ||
| 446 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 447 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 448 | .With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 449 | for(auto& d : sent_data) { | ||
| 450 | byte_stuffer_recv_byte(1, d); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { | ||
| 455 | uint8_t original_data[256]; | ||
| 456 | int i; | ||
| 457 | for(i=0;i<254;i++) { | ||
| 458 | original_data[i] = i + 1; | ||
| 459 | } | ||
| 460 | original_data[254] = 22; | ||
| 461 | original_data[255] = 23; | ||
| 462 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 463 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 464 | .With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 465 | for(auto& d : sent_data) { | ||
| 466 | byte_stuffer_recv_byte(1, d); | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 470 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { | ||
| 471 | uint8_t original_data[255]; | ||
| 472 | int i; | ||
| 473 | for(i=0;i<254;i++) { | ||
| 474 | original_data[i] = i + 1; | ||
| 475 | } | ||
| 476 | original_data[254] = 0; | ||
| 477 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 478 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)) | ||
| 479 | .With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 480 | for(auto& d : sent_data) { | ||
| 481 | byte_stuffer_recv_byte(1, d); | ||
| 482 | } | ||
| 483 | } | ||
diff --git a/quantum/serial_link/tests/frame_router_tests.cpp b/quantum/serial_link/tests/frame_router_tests.cpp new file mode 100644 index 000000000..2bd5bf830 --- /dev/null +++ b/quantum/serial_link/tests/frame_router_tests.cpp | |||
| @@ -0,0 +1,229 @@ | |||
| 1 | /* | ||
| 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 "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | #include <array> | ||
| 28 | extern "C" { | ||
| 29 | #include "serial_link/protocol/transport.h" | ||
| 30 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 31 | #include "serial_link/protocol/frame_router.h" | ||
| 32 | } | ||
| 33 | |||
| 34 | using testing::_; | ||
| 35 | using testing::ElementsAreArray; | ||
| 36 | using testing::Args; | ||
| 37 | |||
| 38 | class FrameRouter : public testing::Test { | ||
| 39 | public: | ||
| 40 | FrameRouter() : | ||
| 41 | current_router_buffer(nullptr) | ||
| 42 | { | ||
| 43 | Instance = this; | ||
| 44 | init_byte_stuffer(); | ||
| 45 | } | ||
| 46 | |||
| 47 | ~FrameRouter() { | ||
| 48 | Instance = nullptr; | ||
| 49 | } | ||
| 50 | |||
| 51 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 52 | auto& buffer = current_router_buffer->send_buffers[link]; | ||
| 53 | std::copy(data, data + size, std::back_inserter(buffer)); | ||
| 54 | } | ||
| 55 | |||
| 56 | void receive_data(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 57 | int i; | ||
| 58 | for(i=0;i<size;i++) { | ||
| 59 | byte_stuffer_recv_byte(link, data[i]); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | void activate_router(uint8_t num) { | ||
| 64 | current_router_buffer = router_buffers + num; | ||
| 65 | router_set_master(num==0); | ||
| 66 | } | ||
| 67 | |||
| 68 | void simulate_transport(uint8_t from, uint8_t to) { | ||
| 69 | activate_router(to); | ||
| 70 | if (from > to) { | ||
| 71 | receive_data(DOWN_LINK, | ||
| 72 | router_buffers[from].send_buffers[UP_LINK].data(), | ||
| 73 | router_buffers[from].send_buffers[UP_LINK].size()); | ||
| 74 | } | ||
| 75 | else if(to > from) { | ||
| 76 | receive_data(UP_LINK, | ||
| 77 | router_buffers[from].send_buffers[DOWN_LINK].data(), | ||
| 78 | router_buffers[from].send_buffers[DOWN_LINK].size()); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | MOCK_METHOD3(transport_recv_frame, void (uint8_t from, uint8_t* data, uint16_t size)); | ||
| 83 | |||
| 84 | std::vector<uint8_t> received_data; | ||
| 85 | |||
| 86 | struct router_buffer { | ||
| 87 | std::vector<uint8_t> send_buffers[2]; | ||
| 88 | }; | ||
| 89 | |||
| 90 | router_buffer router_buffers[8]; | ||
| 91 | router_buffer* current_router_buffer; | ||
| 92 | |||
| 93 | static FrameRouter* Instance; | ||
| 94 | }; | ||
| 95 | |||
| 96 | FrameRouter* FrameRouter::Instance = nullptr; | ||
| 97 | |||
| 98 | |||
| 99 | typedef struct { | ||
| 100 | std::array<uint8_t, 4> data; | ||
| 101 | uint8_t extra[16]; | ||
| 102 | } frame_buffer_t; | ||
| 103 | |||
| 104 | |||
| 105 | extern "C" { | ||
| 106 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 107 | FrameRouter::Instance->send_data(link, data, size); | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
| 112 | FrameRouter::Instance->transport_recv_frame(from, data, size); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) { | ||
| 117 | frame_buffer_t data; | ||
| 118 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 119 | activate_router(0); | ||
| 120 | router_send_frame(0xFF, (uint8_t*)&data, 4); | ||
| 121 | EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 122 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 123 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)) | ||
| 124 | .With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 125 | simulate_transport(0, 1); | ||
| 126 | EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 127 | EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 128 | |||
| 129 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)) | ||
| 130 | .With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 131 | simulate_transport(1, 2); | ||
| 132 | EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); | ||
| 133 | EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0); | ||
| 134 | } | ||
| 135 | |||
| 136 | TEST_F(FrameRouter, master_send_is_received_by_targets) { | ||
| 137 | frame_buffer_t data; | ||
| 138 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 139 | activate_router(0); | ||
| 140 | router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4); | ||
| 141 | EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 142 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 143 | |||
| 144 | simulate_transport(0, 1); | ||
| 145 | EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 146 | EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 147 | |||
| 148 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)) | ||
| 149 | .With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 150 | simulate_transport(1, 2); | ||
| 151 | EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); | ||
| 152 | EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0); | ||
| 153 | |||
| 154 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)) | ||
| 155 | .With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 156 | simulate_transport(2, 3); | ||
| 157 | EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0); | ||
| 158 | EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0); | ||
| 159 | } | ||
| 160 | |||
| 161 | TEST_F(FrameRouter, first_link_sends_to_master) { | ||
| 162 | frame_buffer_t data; | ||
| 163 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 164 | activate_router(1); | ||
| 165 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 166 | EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 167 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 168 | |||
| 169 | EXPECT_CALL(*this, transport_recv_frame(1, _, _)) | ||
| 170 | .With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 171 | simulate_transport(1, 0); | ||
| 172 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 173 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 174 | } | ||
| 175 | |||
| 176 | TEST_F(FrameRouter, second_link_sends_to_master) { | ||
| 177 | frame_buffer_t data; | ||
| 178 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 179 | activate_router(2); | ||
| 180 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 181 | EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0); | ||
| 182 | EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); | ||
| 183 | |||
| 184 | simulate_transport(2, 1); | ||
| 185 | EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 186 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 187 | |||
| 188 | EXPECT_CALL(*this, transport_recv_frame(2, _, _)) | ||
| 189 | .With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 190 | simulate_transport(1, 0); | ||
| 191 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 192 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 193 | } | ||
| 194 | |||
| 195 | TEST_F(FrameRouter, master_sends_to_master_does_nothing) { | ||
| 196 | frame_buffer_t data; | ||
| 197 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 198 | activate_router(0); | ||
| 199 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 200 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 201 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 202 | } | ||
| 203 | |||
| 204 | TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) { | ||
| 205 | frame_buffer_t data; | ||
| 206 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 207 | activate_router(1); | ||
| 208 | router_send_frame(2, (uint8_t*)&data, 4); | ||
| 209 | EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 210 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 211 | } | ||
| 212 | |||
| 213 | TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) { | ||
| 214 | frame_buffer_t data; | ||
| 215 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 216 | activate_router(1); | ||
| 217 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 218 | EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 219 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 220 | |||
| 221 | EXPECT_CALL(*this, transport_recv_frame(_, _, _)) | ||
| 222 | .Times(0); | ||
| 223 | activate_router(0); | ||
| 224 | receive_data(UP_LINK, | ||
| 225 | router_buffers[1].send_buffers[UP_LINK].data(), | ||
| 226 | router_buffers[1].send_buffers[UP_LINK].size()); | ||
| 227 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 228 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 229 | } | ||
diff --git a/quantum/serial_link/tests/frame_validator_tests.cpp b/quantum/serial_link/tests/frame_validator_tests.cpp new file mode 100644 index 000000000..9223af83b --- /dev/null +++ b/quantum/serial_link/tests/frame_validator_tests.cpp | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | /* | ||
| 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 "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | extern "C" { | ||
| 28 | #include "serial_link/protocol/frame_validator.h" | ||
| 29 | } | ||
| 30 | |||
| 31 | using testing::_; | ||
| 32 | using testing::ElementsAreArray; | ||
| 33 | using testing::Args; | ||
| 34 | |||
| 35 | class FrameValidator : public testing::Test { | ||
| 36 | public: | ||
| 37 | FrameValidator() { | ||
| 38 | Instance = this; | ||
| 39 | } | ||
| 40 | |||
| 41 | ~FrameValidator() { | ||
| 42 | Instance = nullptr; | ||
| 43 | } | ||
| 44 | |||
| 45 | MOCK_METHOD3(route_incoming_frame, void (uint8_t link, uint8_t* data, uint16_t size)); | ||
| 46 | MOCK_METHOD3(byte_stuffer_send_frame, void (uint8_t link, uint8_t* data, uint16_t size)); | ||
| 47 | |||
| 48 | static FrameValidator* Instance; | ||
| 49 | }; | ||
| 50 | |||
| 51 | FrameValidator* FrameValidator::Instance = nullptr; | ||
| 52 | |||
| 53 | extern "C" { | ||
| 54 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 55 | FrameValidator::Instance->route_incoming_frame(link, data, size); | ||
| 56 | } | ||
| 57 | |||
| 58 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 59 | FrameValidator::Instance->byte_stuffer_send_frame(link, data, size); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) { | ||
| 64 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)) | ||
| 65 | .Times(0); | ||
| 66 | uint8_t data[] = {1, 2}; | ||
| 67 | validator_recv_frame(0, 0, 1); | ||
| 68 | validator_recv_frame(0, data, 2); | ||
| 69 | validator_recv_frame(0, data, 3); | ||
| 70 | validator_recv_frame(0, data, 4); | ||
| 71 | } | ||
| 72 | |||
| 73 | TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) { | ||
| 74 | uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; | ||
| 75 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)) | ||
| 76 | .With(Args<1, 2>(ElementsAreArray(data, 1))); | ||
| 77 | validator_recv_frame(0, data, 5); | ||
| 78 | } | ||
| 79 | |||
| 80 | TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) { | ||
| 81 | uint8_t data[] = {0x44, 0, 0, 0, 0}; | ||
| 82 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)) | ||
| 83 | .Times(0); | ||
| 84 | validator_recv_frame(1, data, 5); | ||
| 85 | } | ||
| 86 | |||
| 87 | TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) { | ||
| 88 | uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA}; | ||
| 89 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)) | ||
| 90 | .With(Args<1, 2>(ElementsAreArray(data, 4))); | ||
| 91 | validator_recv_frame(1, data, 8); | ||
| 92 | } | ||
| 93 | |||
| 94 | TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) { | ||
| 95 | uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; | ||
| 96 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)) | ||
| 97 | .With(Args<1, 2>(ElementsAreArray(data, 5))); | ||
| 98 | validator_recv_frame(0, data, 9); | ||
| 99 | } | ||
| 100 | |||
| 101 | TEST_F(FrameValidator, sends_one_byte_with_correct_crc) { | ||
| 102 | uint8_t original[] = {0x44, 0, 0, 0, 0}; | ||
| 103 | uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; | ||
| 104 | EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)) | ||
| 105 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 106 | validator_send_frame(0, original, 1); | ||
| 107 | } | ||
| 108 | |||
| 109 | TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) { | ||
| 110 | uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0}; | ||
| 111 | uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; | ||
| 112 | EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)) | ||
| 113 | .With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 114 | validator_send_frame(0, original, 5); | ||
| 115 | } | ||
diff --git a/quantum/serial_link/tests/rules.mk b/quantum/serial_link/tests/rules.mk new file mode 100644 index 000000000..b81515bc5 --- /dev/null +++ b/quantum/serial_link/tests/rules.mk | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | serial_link_byte_stuffer_SRC :=\ | ||
| 2 | $(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \ | ||
| 3 | $(SERIAL_PATH)/protocol/byte_stuffer.c | ||
| 4 | |||
| 5 | serial_link_frame_validator_SRC := \ | ||
| 6 | $(SERIAL_PATH)/tests/frame_validator_tests.cpp \ | ||
| 7 | $(SERIAL_PATH)/protocol/frame_validator.c | ||
| 8 | |||
| 9 | serial_link_frame_router_SRC := \ | ||
| 10 | $(SERIAL_PATH)/tests/frame_router_tests.cpp \ | ||
| 11 | $(SERIAL_PATH)/protocol/byte_stuffer.c \ | ||
| 12 | $(SERIAL_PATH)/protocol/frame_validator.c \ | ||
| 13 | $(SERIAL_PATH)/protocol/frame_router.c | ||
| 14 | |||
| 15 | serial_link_triple_buffered_object_SRC := \ | ||
| 16 | $(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \ | ||
| 17 | $(SERIAL_PATH)/protocol/triple_buffered_object.c | ||
| 18 | |||
| 19 | serial_link_transport_SRC := \ | ||
| 20 | $(SERIAL_PATH)/tests/transport_tests.cpp \ | ||
| 21 | $(SERIAL_PATH)/protocol/transport.c \ | ||
| 22 | $(SERIAL_PATH)/protocol/triple_buffered_object.c | ||
diff --git a/quantum/serial_link/tests/testlist.mk b/quantum/serial_link/tests/testlist.mk new file mode 100644 index 000000000..a80e88884 --- /dev/null +++ b/quantum/serial_link/tests/testlist.mk | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | TEST_LIST +=\ | ||
| 2 | serial_link_byte_stuffer\ | ||
| 3 | serial_link_frame_validator\ | ||
| 4 | serial_link_frame_router\ | ||
| 5 | serial_link_triple_buffered_object\ | ||
| 6 | serial_link_transport \ No newline at end of file | ||
diff --git a/quantum/serial_link/tests/transport_tests.cpp b/quantum/serial_link/tests/transport_tests.cpp new file mode 100644 index 000000000..21b7b165f --- /dev/null +++ b/quantum/serial_link/tests/transport_tests.cpp | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | /* | ||
| 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 "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | |||
| 28 | using testing::_; | ||
| 29 | using testing::ElementsAreArray; | ||
| 30 | using testing::Args; | ||
| 31 | |||
| 32 | extern "C" { | ||
| 33 | #include "serial_link/protocol/transport.h" | ||
| 34 | } | ||
| 35 | |||
| 36 | struct test_object1 { | ||
| 37 | uint32_t test; | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct test_object2 { | ||
| 41 | uint32_t test1; | ||
| 42 | uint32_t test2; | ||
| 43 | }; | ||
| 44 | |||
| 45 | MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1); | ||
| 46 | MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1); | ||
| 47 | SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1); | ||
| 48 | |||
| 49 | static remote_object_t* test_remote_objects[] = { | ||
| 50 | REMOTE_OBJECT(master_to_slave), | ||
| 51 | REMOTE_OBJECT(master_to_single_slave), | ||
| 52 | REMOTE_OBJECT(slave_to_master), | ||
| 53 | }; | ||
| 54 | |||
| 55 | class Transport : public testing::Test { | ||
| 56 | public: | ||
| 57 | Transport() { | ||
| 58 | Instance = this; | ||
| 59 | add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); | ||
| 60 | } | ||
| 61 | |||
| 62 | ~Transport() { | ||
| 63 | Instance = nullptr; | ||
| 64 | reinitialize_serial_link_transport(); | ||
| 65 | } | ||
| 66 | |||
| 67 | MOCK_METHOD0(signal_data_written, void ()); | ||
| 68 | MOCK_METHOD1(router_send_frame, void (uint8_t destination)); | ||
| 69 | |||
| 70 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { | ||
| 71 | router_send_frame(destination); | ||
| 72 | std::copy(data, data + size, std::back_inserter(sent_data)); | ||
| 73 | } | ||
| 74 | |||
| 75 | static Transport* Instance; | ||
| 76 | |||
| 77 | std::vector<uint8_t> sent_data; | ||
| 78 | }; | ||
| 79 | |||
| 80 | Transport* Transport::Instance = nullptr; | ||
| 81 | |||
| 82 | extern "C" { | ||
| 83 | void signal_data_written(void) { | ||
| 84 | Transport::Instance->signal_data_written(); | ||
| 85 | } | ||
| 86 | |||
| 87 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { | ||
| 88 | Transport::Instance->router_send_frame(destination, data, size); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | TEST_F(Transport, write_to_local_signals_an_event) { | ||
| 93 | begin_write_master_to_slave(); | ||
| 94 | EXPECT_CALL(*this, signal_data_written()); | ||
| 95 | end_write_master_to_slave(); | ||
| 96 | begin_write_slave_to_master(); | ||
| 97 | EXPECT_CALL(*this, signal_data_written()); | ||
| 98 | end_write_slave_to_master(); | ||
| 99 | begin_write_master_to_single_slave(1); | ||
| 100 | EXPECT_CALL(*this, signal_data_written()); | ||
| 101 | end_write_master_to_single_slave(1); | ||
| 102 | } | ||
| 103 | |||
| 104 | TEST_F(Transport, writes_from_master_to_all_slaves) { | ||
| 105 | update_transport(); | ||
| 106 | test_object1* obj = begin_write_master_to_slave(); | ||
| 107 | obj->test = 5; | ||
| 108 | EXPECT_CALL(*this, signal_data_written()); | ||
| 109 | end_write_master_to_slave(); | ||
| 110 | EXPECT_CALL(*this, router_send_frame(0xFF)); | ||
| 111 | update_transport(); | ||
| 112 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 113 | test_object1* obj2 = read_master_to_slave(); | ||
| 114 | EXPECT_NE(obj2, nullptr); | ||
| 115 | EXPECT_EQ(obj2->test, 5); | ||
| 116 | } | ||
| 117 | |||
| 118 | TEST_F(Transport, writes_from_slave_to_master) { | ||
| 119 | update_transport(); | ||
| 120 | test_object1* obj = begin_write_slave_to_master(); | ||
| 121 | obj->test = 7; | ||
| 122 | EXPECT_CALL(*this, signal_data_written()); | ||
| 123 | end_write_slave_to_master(); | ||
| 124 | EXPECT_CALL(*this, router_send_frame(0)); | ||
| 125 | update_transport(); | ||
| 126 | transport_recv_frame(3, sent_data.data(), sent_data.size()); | ||
| 127 | test_object1* obj2 = read_slave_to_master(2); | ||
| 128 | EXPECT_EQ(read_slave_to_master(0), nullptr); | ||
| 129 | EXPECT_NE(obj2, nullptr); | ||
| 130 | EXPECT_EQ(obj2->test, 7); | ||
| 131 | } | ||
| 132 | |||
| 133 | TEST_F(Transport, writes_from_master_to_single_slave) { | ||
| 134 | update_transport(); | ||
| 135 | test_object1* obj = begin_write_master_to_single_slave(3); | ||
| 136 | obj->test = 7; | ||
| 137 | EXPECT_CALL(*this, signal_data_written()); | ||
| 138 | end_write_master_to_single_slave(3); | ||
| 139 | EXPECT_CALL(*this, router_send_frame(4)); | ||
| 140 | update_transport(); | ||
| 141 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 142 | test_object1* obj2 = read_master_to_single_slave(); | ||
| 143 | EXPECT_NE(obj2, nullptr); | ||
| 144 | EXPECT_EQ(obj2->test, 7); | ||
| 145 | } | ||
| 146 | |||
| 147 | TEST_F(Transport, ignores_object_with_invalid_id) { | ||
| 148 | update_transport(); | ||
| 149 | test_object1* obj = begin_write_master_to_single_slave(3); | ||
| 150 | obj->test = 7; | ||
| 151 | EXPECT_CALL(*this, signal_data_written()); | ||
| 152 | end_write_master_to_single_slave(3); | ||
| 153 | EXPECT_CALL(*this, router_send_frame(4)); | ||
| 154 | update_transport(); | ||
| 155 | sent_data[sent_data.size() - 1] = 44; | ||
| 156 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 157 | test_object1* obj2 = read_master_to_single_slave(); | ||
| 158 | EXPECT_EQ(obj2, nullptr); | ||
| 159 | } | ||
| 160 | |||
| 161 | TEST_F(Transport, ignores_object_with_size_too_small) { | ||
| 162 | update_transport(); | ||
| 163 | test_object1* obj = begin_write_master_to_slave(); | ||
| 164 | obj->test = 7; | ||
| 165 | EXPECT_CALL(*this, signal_data_written()); | ||
| 166 | end_write_master_to_slave(); | ||
| 167 | EXPECT_CALL(*this, router_send_frame(_)); | ||
| 168 | update_transport(); | ||
| 169 | sent_data[sent_data.size() - 2] = 0; | ||
| 170 | transport_recv_frame(0, sent_data.data(), sent_data.size() - 1); | ||
| 171 | test_object1* obj2 = read_master_to_slave(); | ||
| 172 | EXPECT_EQ(obj2, nullptr); | ||
| 173 | } | ||
| 174 | |||
| 175 | TEST_F(Transport, ignores_object_with_size_too_big) { | ||
| 176 | update_transport(); | ||
| 177 | test_object1* obj = begin_write_master_to_slave(); | ||
| 178 | obj->test = 7; | ||
| 179 | EXPECT_CALL(*this, signal_data_written()); | ||
| 180 | end_write_master_to_slave(); | ||
| 181 | EXPECT_CALL(*this, router_send_frame(_)); | ||
| 182 | update_transport(); | ||
| 183 | sent_data.resize(sent_data.size() + 22); | ||
| 184 | sent_data[sent_data.size() - 1] = 0; | ||
| 185 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 186 | test_object1* obj2 = read_master_to_slave(); | ||
| 187 | EXPECT_EQ(obj2, nullptr); | ||
| 188 | } | ||
diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.cpp b/quantum/serial_link/tests/triple_buffered_object_tests.cpp new file mode 100644 index 000000000..7724bbee9 --- /dev/null +++ b/quantum/serial_link/tests/triple_buffered_object_tests.cpp | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | /* | ||
| 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 "gtest/gtest.h" | ||
| 26 | extern "C" { | ||
| 27 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 28 | } | ||
| 29 | |||
| 30 | struct test_object{ | ||
| 31 | uint8_t state; | ||
| 32 | uint32_t buffer[3]; | ||
| 33 | }; | ||
| 34 | |||
| 35 | test_object test_object; | ||
| 36 | |||
| 37 | class TripleBufferedObject : public testing::Test { | ||
| 38 | public: | ||
| 39 | TripleBufferedObject() { | ||
| 40 | triple_buffer_init((triple_buffer_object_t*)&test_object); | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | |||
| 44 | TEST_F(TripleBufferedObject, writes_and_reads_object) { | ||
| 45 | *triple_buffer_begin_write(&test_object) = 0x3456ABCC; | ||
| 46 | triple_buffer_end_write(&test_object); | ||
| 47 | EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC); | ||
| 48 | } | ||
| 49 | |||
| 50 | TEST_F(TripleBufferedObject, does_not_read_empty) { | ||
| 51 | EXPECT_EQ(triple_buffer_read(&test_object), nullptr); | ||
| 52 | } | ||
| 53 | |||
| 54 | TEST_F(TripleBufferedObject, writes_twice_and_reads_object) { | ||
| 55 | *triple_buffer_begin_write(&test_object) = 0x3456ABCC; | ||
| 56 | triple_buffer_end_write(&test_object); | ||
| 57 | *triple_buffer_begin_write(&test_object) = 0x44778899; | ||
| 58 | triple_buffer_end_write(&test_object); | ||
| 59 | EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899); | ||
| 60 | } | ||
| 61 | |||
| 62 | TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) { | ||
| 63 | *triple_buffer_begin_write(&test_object) = 1; | ||
| 64 | triple_buffer_end_write(&test_object); | ||
| 65 | uint32_t* read = triple_buffer_read(&test_object); | ||
| 66 | *triple_buffer_begin_write(&test_object) = 2; | ||
| 67 | triple_buffer_end_write(&test_object); | ||
| 68 | EXPECT_EQ(*read, 1); | ||
| 69 | EXPECT_EQ(*triple_buffer_read(&test_object), 2); | ||
| 70 | EXPECT_EQ(triple_buffer_read(&test_object), nullptr); | ||
| 71 | } | ||
| 72 | |||
| 73 | TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { | ||
| 74 | *triple_buffer_begin_write(&test_object) = 1; | ||
| 75 | triple_buffer_end_write(&test_object); | ||
| 76 | uint32_t* read = triple_buffer_read(&test_object); | ||
| 77 | *triple_buffer_begin_write(&test_object) = 2; | ||
| 78 | triple_buffer_end_write(&test_object); | ||
| 79 | *triple_buffer_begin_write(&test_object) = 3; | ||
| 80 | triple_buffer_end_write(&test_object); | ||
| 81 | EXPECT_EQ(*read, 1); | ||
| 82 | EXPECT_EQ(*triple_buffer_read(&test_object), 3); | ||
| 83 | EXPECT_EQ(triple_buffer_read(&test_object), nullptr); | ||
| 84 | } | ||
diff --git a/quantum/template/Makefile b/quantum/template/Makefile index 2efa69138..4e2a6f00f 100644 --- a/quantum/template/Makefile +++ b/quantum/template/Makefile | |||
| @@ -1,139 +1,3 @@ | |||
| 1 | #---------------------------------------------------------------------------- | 1 | ifndef MAKEFILE_INCLUDED |
| 2 | # On command line: | 2 | include ../../Makefile |
| 3 | # | 3 | endif \ No newline at end of file |
| 4 | # make all = Make software. | ||
| 5 | # | ||
| 6 | # make clean = Clean out built project files. | ||
| 7 | # | ||
| 8 | # make coff = Convert ELF to AVR COFF. | ||
| 9 | # | ||
| 10 | # make extcoff = Convert ELF to AVR Extended COFF. | ||
| 11 | # | ||
| 12 | # make program = Download the hex file to the device. | ||
| 13 | # Please customize your programmer settings(PROGRAM_CMD) | ||
| 14 | # | ||
| 15 | # make teensy = Download the hex file to the device, using teensy_loader_cli. | ||
| 16 | # (must have teensy_loader_cli installed). | ||
| 17 | # | ||
| 18 | # make dfu = Download the hex file to the device, using dfu-programmer (must | ||
| 19 | # have dfu-programmer installed). | ||
| 20 | # | ||
| 21 | # make flip = Download the hex file to the device, using Atmel FLIP (must | ||
| 22 | # have Atmel FLIP installed). | ||
| 23 | # | ||
| 24 | # make dfu-ee = Download the eeprom file to the device, using dfu-programmer | ||
| 25 | # (must have dfu-programmer installed). | ||
| 26 | # | ||
| 27 | # make flip-ee = Download the eeprom file to the device, using Atmel FLIP | ||
| 28 | # (must have Atmel FLIP installed). | ||
| 29 | # | ||
| 30 | # make debug = Start either simulavr or avarice as specified for debugging, | ||
| 31 | # with avr-gdb or avr-insight as the front end for debugging. | ||
| 32 | # | ||
| 33 | # make filename.s = Just compile filename.c into the assembler code only. | ||
| 34 | # | ||
| 35 | # make filename.i = Create a preprocessed source file for use in submitting | ||
| 36 | # bug reports to the GCC project. | ||
| 37 | # | ||
| 38 | # To rebuild project do "make clean" then "make all". | ||
| 39 | #---------------------------------------------------------------------------- | ||
| 40 | |||
| 41 | # Target file name (without extension). | ||
| 42 | TARGET = %KEYBOARD% | ||
| 43 | |||
| 44 | |||
| 45 | # Directory common source filess exist | ||
| 46 | TOP_DIR = ../.. | ||
| 47 | TMK_DIR = ../../tmk_core | ||
| 48 | |||
| 49 | # Directory keyboard dependent files exist | ||
| 50 | TARGET_DIR = . | ||
| 51 | |||
| 52 | # # project specific files | ||
| 53 | SRC = %KEYBOARD%.c | ||
| 54 | |||
| 55 | ifdef KEYMAP | ||
| 56 | SRC := keymaps/$(KEYMAP).c $(SRC) | ||
| 57 | else | ||
| 58 | SRC := keymaps/default.c $(SRC) | ||
| 59 | endif | ||
| 60 | |||
| 61 | CONFIG_H = config.h | ||
| 62 | |||
| 63 | # MCU name | ||
| 64 | #MCU = at90usb1287 | ||
| 65 | MCU = atmega32u4 | ||
| 66 | |||
| 67 | # Processor frequency. | ||
| 68 | # This will define a symbol, F_CPU, in all source code files equal to the | ||
| 69 | # processor frequency in Hz. You can then use this symbol in your source code to | ||
| 70 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | ||
| 71 | # automatically to create a 32-bit value in your source code. | ||
| 72 | # | ||
| 73 | # This will be an integer division of F_USB below, as it is sourced by | ||
| 74 | # F_USB after it has run through any CPU prescalers. Note that this value | ||
| 75 | # does not *change* the processor frequency - it should merely be updated to | ||
| 76 | # reflect the processor speed set externally so that the code can use accurate | ||
| 77 | # software delays. | ||
| 78 | F_CPU = 16000000 | ||
| 79 | |||
| 80 | |||
| 81 | # | ||
| 82 | # LUFA specific | ||
| 83 | # | ||
| 84 | # Target architecture (see library "Board Types" documentation). | ||
| 85 | ARCH = AVR8 | ||
| 86 | |||
| 87 | # Input clock frequency. | ||
| 88 | # This will define a symbol, F_USB, in all source code files equal to the | ||
| 89 | # input clock frequency (before any prescaling is performed) in Hz. This value may | ||
| 90 | # differ from F_CPU if prescaling is used on the latter, and is required as the | ||
| 91 | # raw input clock is fed directly to the PLL sections of the AVR for high speed | ||
| 92 | # clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' | ||
| 93 | # at the end, this will be done automatically to create a 32-bit value in your | ||
| 94 | # source code. | ||
| 95 | # | ||
| 96 | # If no clock division is performed on the input clock inside the AVR (via the | ||
| 97 | # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | ||
| 98 | F_USB = $(F_CPU) | ||
| 99 | |||
| 100 | # Interrupt driven control endpoint task(+60) | ||
| 101 | OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | ||
| 102 | |||
| 103 | |||
| 104 | # Boot Section Size in *bytes* | ||
| 105 | # Teensy halfKay 512 | ||
| 106 | # Teensy++ halfKay 1024 | ||
| 107 | # Atmel DFU loader 4096 | ||
| 108 | # LUFA bootloader 4096 | ||
| 109 | # USBaspLoader 2048 | ||
| 110 | OPT_DEFS += -DBOOTLOADER_SIZE=512 | ||
| 111 | |||
| 112 | |||
| 113 | # Build Options | ||
| 114 | # comment out to disable the options. | ||
| 115 | # | ||
| 116 | BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) | ||
| 117 | MOUSEKEY_ENABLE = yes # Mouse keys(+4700) | ||
| 118 | EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | ||
| 119 | CONSOLE_ENABLE = yes # Console for debug(+400) | ||
| 120 | COMMAND_ENABLE = yes # Commands for debug and configuration | ||
| 121 | # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE | ||
| 122 | # SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend | ||
| 123 | # NKRO_ENABLE = yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
| 124 | # BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality | ||
| 125 | # MIDI_ENABLE = YES # MIDI controls | ||
| 126 | # UNICODE_ENABLE = YES # Unicode | ||
| 127 | # BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID | ||
| 128 | |||
| 129 | |||
| 130 | # Optimize size but this may cause error "relocation truncated to fit" | ||
| 131 | #EXTRALDFLAGS = -Wl,--relax | ||
| 132 | |||
| 133 | # Search Path | ||
| 134 | VPATH += $(TARGET_DIR) | ||
| 135 | VPATH += $(TOP_DIR) | ||
| 136 | VPATH += $(TMK_DIR) | ||
| 137 | |||
| 138 | include $(TOP_DIR)/quantum/quantum.mk | ||
| 139 | |||
diff --git a/quantum/template/config.h b/quantum/template/config.h index 7d6149f43..b02f0c7eb 100644 --- a/quantum/template/config.h +++ b/quantum/template/config.h | |||
| @@ -32,34 +32,115 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 32 | #define MATRIX_ROWS 2 | 32 | #define MATRIX_ROWS 2 |
| 33 | #define MATRIX_COLS 3 | 33 | #define MATRIX_COLS 3 |
| 34 | 34 | ||
| 35 | // Planck PCB default pin-out | 35 | /* |
| 36 | // Change this to how you wired your keyboard | 36 | * Keyboard Matrix Assignments |
| 37 | // COLS: Left to right, ROWS: Top to bottom | 37 | * |
| 38 | #define COLS (int []){ F1, F0, B0 } | 38 | * Change this to how you wired your keyboard |
| 39 | #define ROWS (int []){ D0, D5 } | 39 | * COLS: AVR pins used for columns, left to right |
| 40 | * ROWS: AVR pins used for rows, top to bottom | ||
| 41 | * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode) | ||
| 42 | * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) | ||
| 43 | * | ||
| 44 | */ | ||
| 45 | #define MATRIX_ROW_PINS { D0, D5 } | ||
| 46 | #define MATRIX_COL_PINS { F1, F0, B0 } | ||
| 47 | #define UNUSED_PINS | ||
| 40 | 48 | ||
| 41 | /* COL2ROW or ROW2COL */ | 49 | /* COL2ROW or ROW2COL */ |
| 42 | #define DIODE_DIRECTION COL2ROW | 50 | #define DIODE_DIRECTION COL2ROW |
| 51 | |||
| 52 | // #define BACKLIGHT_PIN B7 | ||
| 53 | // #define BACKLIGHT_BREATHING | ||
| 54 | // #define BACKLIGHT_LEVELS 3 | ||
| 55 | |||
| 43 | 56 | ||
| 44 | /* define if matrix has ghost */ | 57 | /* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ |
| 58 | #define DEBOUNCING_DELAY 5 | ||
| 59 | |||
| 60 | /* define if matrix has ghost (lacks anti-ghosting diodes) */ | ||
| 45 | //#define MATRIX_HAS_GHOST | 61 | //#define MATRIX_HAS_GHOST |
| 46 | 62 | ||
| 47 | /* number of backlight levels */ | 63 | /* number of backlight levels */ |
| 48 | #define BACKLIGHT_LEVELS 3 | ||
| 49 | |||
| 50 | /* Set 0 if debouncing isn't needed */ | ||
| 51 | #define DEBOUNCE 5 | ||
| 52 | 64 | ||
| 53 | /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ | 65 | /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ |
| 54 | #define LOCKING_SUPPORT_ENABLE | 66 | #define LOCKING_SUPPORT_ENABLE |
| 55 | /* Locking resynchronize hack */ | 67 | /* Locking resynchronize hack */ |
| 56 | #define LOCKING_RESYNC_ENABLE | 68 | #define LOCKING_RESYNC_ENABLE |
| 57 | 69 | ||
| 58 | /* key combination for command */ | 70 | /* |
| 71 | * Force NKRO | ||
| 72 | * | ||
| 73 | * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved | ||
| 74 | * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the | ||
| 75 | * makefile for this to work.) | ||
| 76 | * | ||
| 77 | * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N) | ||
| 78 | * until the next keyboard reset. | ||
| 79 | * | ||
| 80 | * NKRO may prevent your keystrokes from being detected in the BIOS, but it is | ||
| 81 | * fully operational during normal computer usage. | ||
| 82 | * | ||
| 83 | * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N) | ||
| 84 | * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by | ||
| 85 | * bootmagic, NKRO mode will always be enabled until it is toggled again during a | ||
| 86 | * power-up. | ||
| 87 | * | ||
| 88 | */ | ||
| 89 | //#define FORCE_NKRO | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Magic Key Options | ||
| 93 | * | ||
| 94 | * Magic keys are hotkey commands that allow control over firmware functions of | ||
| 95 | * the keyboard. They are best used in combination with the HID Listen program, | ||
| 96 | * found here: https://www.pjrc.com/teensy/hid_listen.html | ||
| 97 | * | ||
| 98 | * The options below allow the magic key functionality to be changed. This is | ||
| 99 | * useful if your keyboard/keypad is missing keys and you want magic key support. | ||
| 100 | * | ||
| 101 | */ | ||
| 102 | |||
| 103 | /* key combination for magic key command */ | ||
| 59 | #define IS_COMMAND() ( \ | 104 | #define IS_COMMAND() ( \ |
| 60 | keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ | 105 | keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ |
| 61 | ) | 106 | ) |
| 62 | 107 | ||
| 108 | /* control how magic key switches layers */ | ||
| 109 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true | ||
| 110 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true | ||
| 111 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false | ||
| 112 | |||
| 113 | /* override magic key keymap */ | ||
| 114 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS | ||
| 115 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS | ||
| 116 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM | ||
| 117 | //#define MAGIC_KEY_HELP1 H | ||
| 118 | //#define MAGIC_KEY_HELP2 SLASH | ||
| 119 | //#define MAGIC_KEY_DEBUG D | ||
| 120 | //#define MAGIC_KEY_DEBUG_MATRIX X | ||
| 121 | //#define MAGIC_KEY_DEBUG_KBD K | ||
| 122 | //#define MAGIC_KEY_DEBUG_MOUSE M | ||
| 123 | //#define MAGIC_KEY_VERSION V | ||
| 124 | //#define MAGIC_KEY_STATUS S | ||
| 125 | //#define MAGIC_KEY_CONSOLE C | ||
| 126 | //#define MAGIC_KEY_LAYER0_ALT1 ESC | ||
| 127 | //#define MAGIC_KEY_LAYER0_ALT2 GRAVE | ||
| 128 | //#define MAGIC_KEY_LAYER0 0 | ||
| 129 | //#define MAGIC_KEY_LAYER1 1 | ||
| 130 | //#define MAGIC_KEY_LAYER2 2 | ||
| 131 | //#define MAGIC_KEY_LAYER3 3 | ||
| 132 | //#define MAGIC_KEY_LAYER4 4 | ||
| 133 | //#define MAGIC_KEY_LAYER5 5 | ||
| 134 | //#define MAGIC_KEY_LAYER6 6 | ||
| 135 | //#define MAGIC_KEY_LAYER7 7 | ||
| 136 | //#define MAGIC_KEY_LAYER8 8 | ||
| 137 | //#define MAGIC_KEY_LAYER9 9 | ||
| 138 | //#define MAGIC_KEY_BOOTLOADER PAUSE | ||
| 139 | //#define MAGIC_KEY_LOCK CAPS | ||
| 140 | //#define MAGIC_KEY_EEPROM E | ||
| 141 | //#define MAGIC_KEY_NKRO N | ||
| 142 | //#define MAGIC_KEY_SLEEP_LED Z | ||
| 143 | |||
| 63 | /* | 144 | /* |
| 64 | * Feature disable options | 145 | * Feature disable options |
| 65 | * These options are also useful to firmware size reduction. | 146 | * These options are also useful to firmware size reduction. |
diff --git a/quantum/template/keymaps/default/Makefile b/quantum/template/keymaps/default/Makefile new file mode 100644 index 000000000..f4671a9d1 --- /dev/null +++ b/quantum/template/keymaps/default/Makefile | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | # Build Options | ||
| 2 | # change to "no" to disable the options, or define them in the Makefile in | ||
| 3 | # the appropriate keymap folder that will get included automatically | ||
| 4 | # | ||
| 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.c b/quantum/template/keymaps/default/keymap.c index 4121fd860..e28a4723e 100644 --- a/quantum/template/keymaps/default.c +++ b/quantum/template/keymaps/default/keymap.c | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | // This is the canonical layout file for the Quantum project. If you want to add another keyboard, | ||
| 2 | // this is the style you want to emulate. | ||
| 3 | |||
| 4 | #include "%KEYBOARD%.h" | 1 | #include "%KEYBOARD%.h" |
| 5 | 2 | ||
| 6 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | 3 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { |
| @@ -28,3 +25,20 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | |||
| 28 | } | 25 | } |
| 29 | return MACRO_NONE; | 26 | return MACRO_NONE; |
| 30 | }; | 27 | }; |
| 28 | |||
| 29 | |||
| 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 index dc163a2f4..b16f4cd76 100644 --- a/quantum/template/README.md +++ b/quantum/template/readme.md | |||
| @@ -3,22 +3,26 @@ | |||
| 3 | 3 | ||
| 4 | ## Quantum MK Firmware | 4 | ## Quantum MK Firmware |
| 5 | 5 | ||
| 6 | For the full Quantum feature list, see [the parent README.md](/README.md). | 6 | For the full Quantum feature list, see [the parent readme](/). |
| 7 | 7 | ||
| 8 | ## Building | 8 | ## Building |
| 9 | 9 | ||
| 10 | Download or clone the whole firmware and navigate to the keyboard/%KEYBOARD% folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use the Teensy Loader to program your .hex file. | 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 | 11 | ||
| 12 | Depending on which keymap you would like to use, you will have to compile slightly differently. | 12 | Depending on which keymap you would like to use, you will have to compile slightly differently. |
| 13 | 13 | ||
| 14 | ### Default | 14 | ### Default |
| 15 | To build with the default keymap, simply run `make`. | 15 | |
| 16 | To build with the default keymap, simply run `make default`. | ||
| 16 | 17 | ||
| 17 | ### Other Keymaps | 18 | ### Other Keymaps |
| 18 | Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create file named `<name>.c` and see keymap document (you can find in top README.md) and existent keymap files. | ||
| 19 | 19 | ||
| 20 | To build the firmware binary hex file with a keymap just do `make` with `KEYMAP` option like: | 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 a keymap like this: | ||
| 23 | |||
| 21 | ``` | 24 | ``` |
| 22 | $ make KEYMAP=[default|jack|<name>] | 25 | $ make [default|jack|<name>] |
| 23 | ``` | 26 | ``` |
| 24 | Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. \ No newline at end of file | 27 | |
| 28 | Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. | ||
diff --git a/quantum/template/rules.mk b/quantum/template/rules.mk new file mode 100644 index 000000000..55898147d --- /dev/null +++ b/quantum/template/rules.mk | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | # MCU name | ||
| 2 | #MCU = at90usb1287 | ||
| 3 | MCU = atmega32u4 | ||
| 4 | |||
| 5 | # Processor frequency. | ||
| 6 | # This will define a symbol, F_CPU, in all source code files equal to the | ||
| 7 | # processor frequency in Hz. You can then use this symbol in your source code to | ||
| 8 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | ||
| 9 | # automatically to create a 32-bit value in your source code. | ||
| 10 | # | ||
| 11 | # This will be an integer division of F_USB below, as it is sourced by | ||
| 12 | # F_USB after it has run through any CPU prescalers. Note that this value | ||
| 13 | # does not *change* the processor frequency - it should merely be updated to | ||
| 14 | # reflect the processor speed set externally so that the code can use accurate | ||
| 15 | # software delays. | ||
| 16 | F_CPU = 16000000 | ||
| 17 | |||
| 18 | |||
| 19 | # | ||
| 20 | # LUFA specific | ||
| 21 | # | ||
| 22 | # Target architecture (see library "Board Types" documentation). | ||
| 23 | ARCH = AVR8 | ||
| 24 | |||
| 25 | # Input clock frequency. | ||
| 26 | # This will define a symbol, F_USB, in all source code files equal to the | ||
| 27 | # input clock frequency (before any prescaling is performed) in Hz. This value may | ||
| 28 | # differ from F_CPU if prescaling is used on the latter, and is required as the | ||
| 29 | # raw input clock is fed directly to the PLL sections of the AVR for high speed | ||
| 30 | # clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' | ||
| 31 | # at the end, this will be done automatically to create a 32-bit value in your | ||
| 32 | # source code. | ||
| 33 | # | ||
| 34 | # If no clock division is performed on the input clock inside the AVR (via the | ||
| 35 | # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | ||
| 36 | F_USB = $(F_CPU) | ||
| 37 | |||
| 38 | # Interrupt driven control endpoint task(+60) | ||
| 39 | OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | ||
| 40 | |||
| 41 | |||
| 42 | # Boot Section Size in *bytes* | ||
| 43 | # Teensy halfKay 512 | ||
| 44 | # Teensy++ halfKay 1024 | ||
| 45 | # Atmel DFU loader 4096 | ||
| 46 | # LUFA bootloader 4096 | ||
| 47 | # USBaspLoader 2048 | ||
| 48 | OPT_DEFS += -DBOOTLOADER_SIZE=512 | ||
| 49 | |||
| 50 | |||
| 51 | # Build Options | ||
| 52 | # change yes to no to disable | ||
| 53 | # | ||
| 54 | BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) | ||
| 55 | MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) | ||
| 56 | EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) | ||
| 57 | CONSOLE_ENABLE ?= yes # Console for debug(+400) | ||
| 58 | COMMAND_ENABLE ?= yes # Commands for debug and configuration | ||
| 59 | # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE | ||
| 60 | SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend | ||
| 61 | # if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
| 62 | NKRO_ENABLE ?= no # USB Nkey Rollover | ||
| 63 | BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default | ||
| 64 | MIDI_ENABLE ?= no # MIDI controls | ||
| 65 | UNICODE_ENABLE ?= no # Unicode | ||
| 66 | BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID | ||
| 67 | AUDIO_ENABLE ?= no # Audio output on port C6 | ||
diff --git a/quantum/template/template.c b/quantum/template/template.c index 7be7dfc3d..5ef349583 100644 --- a/quantum/template/template.c +++ b/quantum/template/template.c | |||
| @@ -1,29 +1,28 @@ | |||
| 1 | #include "%KEYBOARD%.h" | 1 | #include "%KEYBOARD%.h" |
| 2 | 2 | ||
| 3 | __attribute__ ((weak)) | 3 | void matrix_init_kb(void) { |
| 4 | void * matrix_init_user(void) { | ||
| 5 | // leave these blank | ||
| 6 | }; | ||
| 7 | |||
| 8 | __attribute__ ((weak)) | ||
| 9 | void * matrix_scan_user(void) { | ||
| 10 | // leave these blank | ||
| 11 | }; | ||
| 12 | |||
| 13 | void * matrix_init_kb(void) { | ||
| 14 | // put your keyboard start-up code here | 4 | // put your keyboard start-up code here |
| 15 | // runs once when the firmware starts up | 5 | // runs once when the firmware starts up |
| 16 | 6 | ||
| 17 | if (matrix_init_user) { | 7 | matrix_init_user(); |
| 18 | (*matrix_init_user)(); | 8 | } |
| 19 | } | ||
| 20 | }; | ||
| 21 | 9 | ||
| 22 | void * matrix_scan_kb(void) { | 10 | void matrix_scan_kb(void) { |
| 23 | // put your looping keyboard code here | 11 | // put your looping keyboard code here |
| 24 | // runs every cycle (a lot) | 12 | // runs every cycle (a lot) |
| 25 | 13 | ||
| 26 | if (matrix_scan_user) { | 14 | matrix_scan_user(); |
| 27 | (*matrix_scan_user)(); | 15 | } |
| 28 | } | 16 | |
| 29 | }; \ No newline at end of file | 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_record_user(keycode, 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 index d4d78e4c9..cd78a54e3 100644 --- a/quantum/template/template.h +++ b/quantum/template/template.h | |||
| @@ -1,10 +1,7 @@ | |||
| 1 | #ifndef %KEYBOARD_UPPERCASE%_H | 1 | #ifndef %KEYBOARD_UPPERCASE%_H |
| 2 | #define %KEYBOARD_UPPERCASE%_H | 2 | #define %KEYBOARD_UPPERCASE%_H |
| 3 | 3 | ||
| 4 | #include "matrix.h" | 4 | #include "quantum.h" |
| 5 | #include "keymap_common.h" | ||
| 6 | #include "backlight.h" | ||
| 7 | #include <stddef.h> | ||
| 8 | 5 | ||
| 9 | // This a shortcut to help you visually see your layout. | 6 | // This a shortcut to help you visually see your layout. |
| 10 | // The following is an example using the Planck MIT layout | 7 | // The following is an example using the Planck MIT layout |
| @@ -12,14 +9,11 @@ | |||
| 12 | // The second converts the arguments into a two-dimensional array | 9 | // The second converts the arguments into a two-dimensional array |
| 13 | #define KEYMAP( \ | 10 | #define KEYMAP( \ |
| 14 | k00, k01, k02, \ | 11 | k00, k01, k02, \ |
| 15 | k10, k11, \ | 12 | k10, k11 \ |
| 16 | ) \ | 13 | ) \ |
| 17 | { \ | 14 | { \ |
| 18 | { k00, k01, k02 }, \ | 15 | { k00, k01, k02 }, \ |
| 19 | { k10, KC_NO, k11 }, \ | 16 | { k10, KC_NO, k11 }, \ |
| 20 | } | 17 | } |
| 21 | 18 | ||
| 22 | void * matrix_init_user(void); | 19 | #endif |
| 23 | void * matrix_scan_user(void); | ||
| 24 | |||
| 25 | #endif \ No newline at end of file | ||
diff --git a/quantum/tools/eeprom_reset.hex b/quantum/tools/eeprom_reset.hex new file mode 100644 index 000000000..a8a75389f --- /dev/null +++ b/quantum/tools/eeprom_reset.hex | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | :10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 | ||
| 2 | :10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 | ||
| 3 | :10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 | ||
| 4 | :10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 | ||
| 5 | :10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 | ||
| 6 | :10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 | ||
| 7 | :10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 | ||
| 8 | :10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 | ||
| 9 | :00000001FF | ||
diff --git a/quantum/tools/readme.md b/quantum/tools/readme.md new file mode 100644 index 000000000..5f355256d --- /dev/null +++ b/quantum/tools/readme.md | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | `eeprom_reset.hex` is to reset the eeprom on the Atmega32u4, like this: | ||
| 2 | |||
| 3 | dfu-programmer atmega32u4 erase | ||
| 4 | dfu-programmer atmega32u4 flash --eeprom eeprom_reset.hex | ||
| 5 | |||
| 6 | You'll need to reflash afterwards, because DFU requires the flash to be erased before messing with the eeprom. | ||
diff --git a/quantum/variable_trace.c b/quantum/variable_trace.c new file mode 100644 index 000000000..de580244c --- /dev/null +++ b/quantum/variable_trace.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | #include "variable_trace.h" | ||
| 2 | #include <stddef.h> | ||
| 3 | #include <string.h> | ||
| 4 | |||
| 5 | #ifdef NO_PRINT | ||
| 6 | #error "You need undef NO_PRINT to use the variable trace feature" | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #ifndef CONSOLE_ENABLE | ||
| 10 | #error "The console needs to be enabled in the makefile to use the variable trace feature" | ||
| 11 | #endif | ||
| 12 | |||
| 13 | |||
| 14 | #define NUM_TRACED_VARIABLES 1 | ||
| 15 | #ifndef MAX_VARIABLE_TRACE_SIZE | ||
| 16 | #define MAX_VARIABLE_TRACE_SIZE 4 | ||
| 17 | #endif | ||
| 18 | |||
| 19 | typedef struct { | ||
| 20 | const char* name; | ||
| 21 | void* addr; | ||
| 22 | unsigned size; | ||
| 23 | const char* func; | ||
| 24 | int line; | ||
| 25 | uint8_t last_value[MAX_VARIABLE_TRACE_SIZE]; | ||
| 26 | |||
| 27 | } traced_variable_t; | ||
| 28 | |||
| 29 | static traced_variable_t traced_variables[NUM_TRACED_VARIABLES]; | ||
| 30 | |||
| 31 | void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line) { | ||
| 32 | verify_traced_variables(func, line); | ||
| 33 | if (size > MAX_VARIABLE_TRACE_SIZE) { | ||
| 34 | #if defined(__AVR__) | ||
| 35 | xprintf("Traced variable \"%S\" exceeds the maximum size %d\n", name, size); | ||
| 36 | #else | ||
| 37 | xprintf("Traced variable \"%s\" exceeds the maximum size %d\n", name, size); | ||
| 38 | #endif | ||
| 39 | size = MAX_VARIABLE_TRACE_SIZE; | ||
| 40 | } | ||
| 41 | int index = -1; | ||
| 42 | for (int i = 0; i < NUM_TRACED_VARIABLES; i++) { | ||
| 43 | if (index == -1 && traced_variables[i].addr == NULL){ | ||
| 44 | index = i; | ||
| 45 | } | ||
| 46 | else if (strcmp_P(name, traced_variables[i].name)==0) { | ||
| 47 | index = i; | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | if (index == -1) { | ||
| 53 | xprintf("You can only trace %d variables at the same time\n", NUM_TRACED_VARIABLES); | ||
| 54 | return; | ||
| 55 | } | ||
| 56 | |||
| 57 | traced_variable_t* t = &traced_variables[index]; | ||
| 58 | t->name = name; | ||
| 59 | t->addr = addr; | ||
| 60 | t->size = size; | ||
| 61 | t->func = func; | ||
| 62 | t->line = line; | ||
| 63 | memcpy(&t->last_value[0], addr, size); | ||
| 64 | |||
| 65 | } | ||
| 66 | |||
| 67 | void remove_traced_variable(const char* name, const char* func, int line) { | ||
| 68 | verify_traced_variables(func, line); | ||
| 69 | for (int i = 0; i < NUM_TRACED_VARIABLES; i++) { | ||
| 70 | if (strcmp_P(name, traced_variables[i].name)==0) { | ||
| 71 | traced_variables[i].name = 0; | ||
| 72 | traced_variables[i].addr = NULL; | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | void verify_traced_variables(const char* func, int line) { | ||
| 79 | for (int i = 0; i < NUM_TRACED_VARIABLES; i++) { | ||
| 80 | traced_variable_t* t = &traced_variables[i]; | ||
| 81 | if (t->addr != NULL && t->name != NULL) { | ||
| 82 | if (memcmp(t->last_value, t->addr, t->size)!=0){ | ||
| 83 | #if defined(__AVR__) | ||
| 84 | xprintf("Traced variable \"%S\" has been modified\n", t->name); | ||
| 85 | xprintf("Between %S:%d\n", t->func, t->line); | ||
| 86 | xprintf("And %S:%d\n", func, line); | ||
| 87 | |||
| 88 | #else | ||
| 89 | xprintf("Traced variable \"%s\" has been modified\n", t->name); | ||
| 90 | xprintf("Between %s:%d\n", t->func, t->line); | ||
| 91 | xprintf("And %s:%d\n", func, line); | ||
| 92 | #endif | ||
| 93 | xprintf("Previous value "); | ||
| 94 | for (int j=0; j<t->size;j++) { | ||
| 95 | print_hex8(t->last_value[j]); | ||
| 96 | } | ||
| 97 | xprintf("\nNew value "); | ||
| 98 | uint8_t* addr = (uint8_t*)(t->addr); | ||
| 99 | for (int j=0; j<t->size;j++) { | ||
| 100 | print_hex8(addr[j]); | ||
| 101 | } | ||
| 102 | xprintf("\n"); | ||
| 103 | memcpy(t->last_value, addr, t->size); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | t->func = func; | ||
| 108 | t->line = line; | ||
| 109 | } | ||
| 110 | } | ||
diff --git a/quantum/variable_trace.h b/quantum/variable_trace.h new file mode 100644 index 000000000..46bd82786 --- /dev/null +++ b/quantum/variable_trace.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #ifndef VARIABLE_TRACE_H | ||
| 2 | #define VARIABLE_TRACE_H | ||
| 3 | |||
| 4 | // For more information about the variable tracing see the readme. | ||
| 5 | |||
| 6 | #include "print.h" | ||
| 7 | |||
| 8 | #ifdef NUM_TRACED_VARIABLES | ||
| 9 | |||
| 10 | // Start tracing a variable at the memory address addr | ||
| 11 | // The name can be anything and is used only for reporting | ||
| 12 | // The size should usually be the same size as the variable you are interested in | ||
| 13 | #define ADD_TRACED_VARIABLE(name, addr, size) \ | ||
| 14 | add_traced_variable(PSTR(name), (void*)addr, size, PSTR(__FILE__), __LINE__) | ||
| 15 | |||
| 16 | // Stop tracing the variable with the given name | ||
| 17 | #define REMOVE_TRACED_VARIABLE(name) remove_traced_variable(PSTR(name), PSTR(__FILE__), __LINE__) | ||
| 18 | |||
| 19 | // Call to get messages when the variable has been changed | ||
| 20 | #define VERIFY_TRACED_VARIABLES() verify_traced_variables(PSTR(__FILE__), __LINE__) | ||
| 21 | |||
| 22 | #else | ||
| 23 | |||
| 24 | #define ADD_TRACED_VARIABLE(name, addr, size) | ||
| 25 | #define REMOVE_TRACED_VARIABLE(name) | ||
| 26 | #define VERIFY_TRACED_VARIABLES() | ||
| 27 | |||
| 28 | #endif | ||
| 29 | |||
| 30 | // Don't call directly, use the macros instead | ||
| 31 | void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line); | ||
| 32 | void remove_traced_variable(const char* name, const char* func, int line); | ||
| 33 | void verify_traced_variables(const char* func, int line); | ||
| 34 | #endif | ||
diff --git a/quantum/visualizer/LICENSE.md b/quantum/visualizer/LICENSE.md new file mode 100644 index 000000000..22d4c3f08 --- /dev/null +++ b/quantum/visualizer/LICENSE.md | |||
| @@ -0,0 +1,29 @@ | |||
| 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/led_test.c b/quantum/visualizer/led_test.c new file mode 100644 index 000000000..a9abace8d --- /dev/null +++ b/quantum/visualizer/led_test.c | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | /* | ||
| 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 "led_test.h" | ||
| 25 | #include "gfx.h" | ||
| 26 | #include "math.h" | ||
| 27 | |||
| 28 | #define CROSSFADE_TIME 1000 | ||
| 29 | #define GRADIENT_TIME 3000 | ||
| 30 | |||
| 31 | keyframe_animation_t led_test_animation = { | ||
| 32 | .num_frames = 14, | ||
| 33 | .loop = true, | ||
| 34 | .frame_lengths = { | ||
| 35 | gfxMillisecondsToTicks(1000), // fade in | ||
| 36 | gfxMillisecondsToTicks(1000), // no op (leds on) | ||
| 37 | gfxMillisecondsToTicks(1000), // fade out | ||
| 38 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 39 | gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in) | ||
| 40 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 41 | gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom | ||
| 42 | 0, // mirror leds | ||
| 43 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 44 | gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out) | ||
| 45 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 46 | gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom | ||
| 47 | 0, // normal leds | ||
| 48 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 49 | |||
| 50 | }, | ||
| 51 | .frame_functions = { | ||
| 52 | keyframe_fade_in_all_leds, | ||
| 53 | keyframe_no_operation, | ||
| 54 | keyframe_fade_out_all_leds, | ||
| 55 | keyframe_led_crossfade, | ||
| 56 | keyframe_led_left_to_right_gradient, | ||
| 57 | keyframe_led_crossfade, | ||
| 58 | keyframe_led_top_to_bottom_gradient, | ||
| 59 | keyframe_mirror_led_orientation, | ||
| 60 | keyframe_led_crossfade, | ||
| 61 | keyframe_led_left_to_right_gradient, | ||
| 62 | keyframe_led_crossfade, | ||
| 63 | keyframe_led_top_to_bottom_gradient, | ||
| 64 | keyframe_normal_led_orientation, | ||
| 65 | keyframe_led_crossfade, | ||
| 66 | }, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) { | ||
| 70 | int frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 71 | int current_pos = frame_length - animation->time_left_in_frame; | ||
| 72 | int delta = to - from; | ||
| 73 | int luma = (delta * current_pos) / frame_length; | ||
| 74 | luma += from; | ||
| 75 | return luma; | ||
| 76 | } | ||
| 77 | |||
| 78 | static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint8_t from, uint8_t to) { | ||
| 79 | uint8_t luma = fade_led_color(animation, from, to); | ||
| 80 | color_t color = LUMA2COLOR(luma); | ||
| 81 | gdispGClear(LED_DISPLAY, color); | ||
| 82 | } | ||
| 83 | |||
| 84 | // TODO: Should be customizable per keyboard | ||
| 85 | #define NUM_ROWS 7 | ||
| 86 | #define NUM_COLS 7 | ||
| 87 | |||
| 88 | static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS]; | ||
| 89 | static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS]; | ||
| 90 | |||
| 91 | static uint8_t compute_gradient_color(float t, float index, float num) { | ||
| 92 | const float two_pi = M_2_PI; | ||
| 93 | float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi; | ||
| 94 | float x = t * two_pi + normalized_index; | ||
| 95 | float v = 0.5 * (cosf(x) + 1.0f); | ||
| 96 | return (uint8_t)(255.0f * v); | ||
| 97 | } | ||
| 98 | |||
| 99 | bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 100 | (void)state; | ||
| 101 | keyframe_fade_all_leds_from_to(animation, 0, 255); | ||
| 102 | return true; | ||
| 103 | } | ||
| 104 | |||
| 105 | bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 106 | (void)state; | ||
| 107 | keyframe_fade_all_leds_from_to(animation, 255, 0); | ||
| 108 | return true; | ||
| 109 | } | ||
| 110 | |||
| 111 | bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 112 | (void)state; | ||
| 113 | float frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 114 | float current_pos = frame_length - animation->time_left_in_frame; | ||
| 115 | float t = current_pos / frame_length; | ||
| 116 | for (int i=0; i< NUM_COLS; i++) { | ||
| 117 | uint8_t color = compute_gradient_color(t, i, NUM_COLS); | ||
| 118 | gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color)); | ||
| 119 | } | ||
| 120 | return true; | ||
| 121 | } | ||
| 122 | |||
| 123 | bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 124 | (void)state; | ||
| 125 | float frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 126 | float current_pos = frame_length - animation->time_left_in_frame; | ||
| 127 | float t = current_pos / frame_length; | ||
| 128 | for (int i=0; i< NUM_ROWS; i++) { | ||
| 129 | uint8_t color = compute_gradient_color(t, i, NUM_ROWS); | ||
| 130 | gdispGDrawLine(LED_DISPLAY, 0, i, NUM_COLS - 1, i, LUMA2COLOR(color)); | ||
| 131 | } | ||
| 132 | return true; | ||
| 133 | } | ||
| 134 | |||
| 135 | static void copy_current_led_state(uint8_t* dest) { | ||
| 136 | for (int i=0;i<NUM_ROWS;i++) { | ||
| 137 | for (int j=0;j<NUM_COLS;j++) { | ||
| 138 | dest[i*NUM_COLS + j] = gdispGGetPixelColor(LED_DISPLAY, j, i); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 143 | (void)state; | ||
| 144 | if (animation->first_update_of_frame) { | ||
| 145 | copy_current_led_state(&crossfade_start_frame[0][0]); | ||
| 146 | run_next_keyframe(animation, state); | ||
| 147 | copy_current_led_state(&crossfade_end_frame[0][0]); | ||
| 148 | } | ||
| 149 | for (int i=0;i<NUM_ROWS;i++) { | ||
| 150 | for (int j=0;j<NUM_COLS;j++) { | ||
| 151 | color_t color = LUMA2COLOR(fade_led_color(animation, crossfade_start_frame[i][j], crossfade_end_frame[i][j])); | ||
| 152 | gdispGDrawPixel(LED_DISPLAY, j, i, color); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | return true; | ||
| 156 | } | ||
| 157 | |||
| 158 | bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 159 | (void)state; | ||
| 160 | (void)animation; | ||
| 161 | gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180); | ||
| 162 | return false; | ||
| 163 | } | ||
| 164 | |||
| 165 | bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 166 | (void)state; | ||
| 167 | (void)animation; | ||
| 168 | gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0); | ||
| 169 | return false; | ||
| 170 | } | ||
diff --git a/quantum/visualizer/led_test.h b/quantum/visualizer/led_test.h new file mode 100644 index 000000000..5e2325753 --- /dev/null +++ b/quantum/visualizer/led_test.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 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 TMK_VISUALIZER_LED_TEST_H_ | ||
| 26 | #define TMK_VISUALIZER_LED_TEST_H_ | ||
| 27 | |||
| 28 | #include "visualizer.h" | ||
| 29 | |||
| 30 | bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 31 | bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 32 | bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 33 | bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 34 | bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 35 | bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 36 | bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 37 | |||
| 38 | extern keyframe_animation_t led_test_animation; | ||
| 39 | |||
| 40 | |||
| 41 | #endif /* TMK_VISUALIZER_LED_TEST_H_ */ | ||
diff --git a/quantum/visualizer/readme.md b/quantum/visualizer/readme.md new file mode 100644 index 000000000..545ba2270 --- /dev/null +++ b/quantum/visualizer/readme.md | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | # A visualization library for the TMK keyboard firmware | ||
| 2 | |||
| 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/visualizer.c b/quantum/visualizer/visualizer.c new file mode 100644 index 000000000..54f6faaa4 --- /dev/null +++ b/quantum/visualizer/visualizer.c | |||
| @@ -0,0 +1,545 @@ | |||
| 1 | /* | ||
| 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 "config.h" | ||
| 27 | #include <string.h> | ||
| 28 | #ifdef PROTOCOL_CHIBIOS | ||
| 29 | #include "ch.h" | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #include "gfx.h" | ||
| 33 | |||
| 34 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 35 | #include "lcd_backlight.h" | ||
| 36 | #endif | ||
| 37 | |||
| 38 | //#define DEBUG_VISUALIZER | ||
| 39 | |||
| 40 | #ifdef DEBUG_VISUALIZER | ||
| 41 | #include "debug.h" | ||
| 42 | #else | ||
| 43 | #include "nodebug.h" | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifdef SERIAL_LINK_ENABLE | ||
| 47 | #include "serial_link/protocol/transport.h" | ||
| 48 | #include "serial_link/system/serial_link.h" | ||
| 49 | #endif | ||
| 50 | |||
| 51 | // Define this in config.h | ||
| 52 | #ifndef VISUALIZER_THREAD_PRIORITY | ||
| 53 | #define "Visualizer thread priority not defined" | ||
| 54 | #endif | ||
| 55 | |||
| 56 | |||
| 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 bool visualizer_enabled = false; | ||
| 72 | |||
| 73 | #define MAX_SIMULTANEOUS_ANIMATIONS 4 | ||
| 74 | static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {}; | ||
| 75 | |||
| 76 | #ifdef SERIAL_LINK_ENABLE | ||
| 77 | MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t); | ||
| 78 | |||
| 79 | static remote_object_t* remote_objects[] = { | ||
| 80 | REMOTE_OBJECT(current_status), | ||
| 81 | }; | ||
| 82 | |||
| 83 | #endif | ||
| 84 | |||
| 85 | GDisplay* LCD_DISPLAY = 0; | ||
| 86 | GDisplay* LED_DISPLAY = 0; | ||
| 87 | |||
| 88 | __attribute__((weak)) | ||
| 89 | GDisplay* get_lcd_display(void) { | ||
| 90 | return gdispGetDisplay(0); | ||
| 91 | } | ||
| 92 | |||
| 93 | __attribute__((weak)) | ||
| 94 | GDisplay* get_led_display(void) { | ||
| 95 | return gdispGetDisplay(1); | ||
| 96 | } | ||
| 97 | |||
| 98 | void start_keyframe_animation(keyframe_animation_t* animation) { | ||
| 99 | animation->current_frame = -1; | ||
| 100 | animation->time_left_in_frame = 0; | ||
| 101 | animation->need_update = true; | ||
| 102 | int free_index = -1; | ||
| 103 | for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) { | ||
| 104 | if (animations[i] == animation) { | ||
| 105 | return; | ||
| 106 | } | ||
| 107 | if (free_index == -1 && animations[i] == NULL) { | ||
| 108 | free_index=i; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | if (free_index!=-1) { | ||
| 112 | animations[free_index] = animation; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | void stop_keyframe_animation(keyframe_animation_t* animation) { | ||
| 117 | animation->current_frame = animation->num_frames; | ||
| 118 | animation->time_left_in_frame = 0; | ||
| 119 | animation->need_update = true; | ||
| 120 | animation->first_update_of_frame = false; | ||
| 121 | animation->last_update_of_frame = false; | ||
| 122 | for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) { | ||
| 123 | if (animations[i] == animation) { | ||
| 124 | animations[i] = NULL; | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | void stop_all_keyframe_animations(void) { | ||
| 131 | for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) { | ||
| 132 | if (animations[i]) { | ||
| 133 | animations[i]->current_frame = animations[i]->num_frames; | ||
| 134 | animations[i]->time_left_in_frame = 0; | ||
| 135 | animations[i]->need_update = true; | ||
| 136 | animations[i]->first_update_of_frame = false; | ||
| 137 | animations[i]->last_update_of_frame = false; | ||
| 138 | animations[i] = NULL; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) { | ||
| 144 | // TODO: Clean up this messy code | ||
| 145 | dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame, | ||
| 146 | animation->time_left_in_frame, delta); | ||
| 147 | if (animation->current_frame == animation->num_frames) { | ||
| 148 | animation->need_update = false; | ||
| 149 | return false; | ||
| 150 | } | ||
| 151 | if (animation->current_frame == -1) { | ||
| 152 | animation->current_frame = 0; | ||
| 153 | animation->time_left_in_frame = animation->frame_lengths[0]; | ||
| 154 | animation->need_update = true; | ||
| 155 | animation->first_update_of_frame = true; | ||
| 156 | } else { | ||
| 157 | animation->time_left_in_frame -= delta; | ||
| 158 | while (animation->time_left_in_frame <= 0) { | ||
| 159 | int left = animation->time_left_in_frame; | ||
| 160 | if (animation->need_update) { | ||
| 161 | animation->time_left_in_frame = 0; | ||
| 162 | animation->last_update_of_frame = true; | ||
| 163 | (*animation->frame_functions[animation->current_frame])(animation, state); | ||
| 164 | animation->last_update_of_frame = false; | ||
| 165 | } | ||
| 166 | animation->current_frame++; | ||
| 167 | animation->need_update = true; | ||
| 168 | animation->first_update_of_frame = true; | ||
| 169 | if (animation->current_frame == animation->num_frames) { | ||
| 170 | if (animation->loop) { | ||
| 171 | animation->current_frame = 0; | ||
| 172 | } | ||
| 173 | else { | ||
| 174 | stop_keyframe_animation(animation); | ||
| 175 | return false; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | delta = -left; | ||
| 179 | animation->time_left_in_frame = animation->frame_lengths[animation->current_frame]; | ||
| 180 | animation->time_left_in_frame -= delta; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | if (animation->need_update) { | ||
| 184 | animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state); | ||
| 185 | animation->first_update_of_frame = false; | ||
| 186 | } | ||
| 187 | |||
| 188 | systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame; | ||
| 189 | if (wanted_sleep < *sleep_time) { | ||
| 190 | *sleep_time = wanted_sleep; | ||
| 191 | } | ||
| 192 | |||
| 193 | return true; | ||
| 194 | } | ||
| 195 | |||
| 196 | void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 197 | int next_frame = animation->current_frame + 1; | ||
| 198 | if (next_frame == animation->num_frames) { | ||
| 199 | next_frame = 0; | ||
| 200 | } | ||
| 201 | keyframe_animation_t temp_animation = *animation; | ||
| 202 | temp_animation.current_frame = next_frame; | ||
| 203 | temp_animation.time_left_in_frame = animation->frame_lengths[next_frame]; | ||
| 204 | temp_animation.first_update_of_frame = true; | ||
| 205 | temp_animation.last_update_of_frame = false; | ||
| 206 | temp_animation.need_update = false; | ||
| 207 | visualizer_state_t temp_state = *state; | ||
| 208 | (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state); | ||
| 209 | } | ||
| 210 | |||
| 211 | bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 212 | (void)animation; | ||
| 213 | (void)state; | ||
| 214 | return false; | ||
| 215 | } | ||
| 216 | |||
| 217 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 218 | bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 219 | int frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 220 | int current_pos = frame_length - animation->time_left_in_frame; | ||
| 221 | uint8_t t_h = LCD_HUE(state->target_lcd_color); | ||
| 222 | uint8_t t_s = LCD_SAT(state->target_lcd_color); | ||
| 223 | uint8_t t_i = LCD_INT(state->target_lcd_color); | ||
| 224 | uint8_t p_h = LCD_HUE(state->prev_lcd_color); | ||
| 225 | uint8_t p_s = LCD_SAT(state->prev_lcd_color); | ||
| 226 | uint8_t p_i = LCD_INT(state->prev_lcd_color); | ||
| 227 | |||
| 228 | uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around | ||
| 229 | int d_h2 = t_h - p_h; | ||
| 230 | // Chose the shortest way around | ||
| 231 | int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1; | ||
| 232 | int d_s = t_s - p_s; | ||
| 233 | int d_i = t_i - p_i; | ||
| 234 | |||
| 235 | int hue = (d_h * current_pos) / frame_length; | ||
| 236 | int sat = (d_s * current_pos) / frame_length; | ||
| 237 | int intensity = (d_i * current_pos) / frame_length; | ||
| 238 | //dprintf("%X -> %X = %X\n", p_h, t_h, hue); | ||
| 239 | hue += p_h; | ||
| 240 | sat += p_s; | ||
| 241 | intensity += p_i; | ||
| 242 | state->current_lcd_color = LCD_COLOR(hue, sat, intensity); | ||
| 243 | lcd_backlight_color( | ||
| 244 | LCD_HUE(state->current_lcd_color), | ||
| 245 | LCD_SAT(state->current_lcd_color), | ||
| 246 | LCD_INT(state->current_lcd_color)); | ||
| 247 | |||
| 248 | return true; | ||
| 249 | } | ||
| 250 | |||
| 251 | bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 252 | (void)animation; | ||
| 253 | state->prev_lcd_color = state->target_lcd_color; | ||
| 254 | state->current_lcd_color = state->target_lcd_color; | ||
| 255 | lcd_backlight_color( | ||
| 256 | LCD_HUE(state->current_lcd_color), | ||
| 257 | LCD_SAT(state->current_lcd_color), | ||
| 258 | LCD_INT(state->current_lcd_color)); | ||
| 259 | return false; | ||
| 260 | } | ||
| 261 | #endif // LCD_BACKLIGHT_ENABLE | ||
| 262 | |||
| 263 | #ifdef LCD_ENABLE | ||
| 264 | bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 265 | (void)animation; | ||
| 266 | gdispClear(White); | ||
| 267 | gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black); | ||
| 268 | gdispFlush(); | ||
| 269 | return false; | ||
| 270 | } | ||
| 271 | |||
| 272 | static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) { | ||
| 273 | for (int i=0; i<16;i++) | ||
| 274 | { | ||
| 275 | uint32_t mask = (1u << i); | ||
| 276 | if (default_layer & mask) { | ||
| 277 | if (layer & mask) { | ||
| 278 | *buffer = 'B'; | ||
| 279 | } else { | ||
| 280 | *buffer = 'D'; | ||
| 281 | } | ||
| 282 | } else if (layer & mask) { | ||
| 283 | *buffer = '1'; | ||
| 284 | } else { | ||
| 285 | *buffer = '0'; | ||
| 286 | } | ||
| 287 | ++buffer; | ||
| 288 | |||
| 289 | if (i==3 || i==7 || i==11) { | ||
| 290 | *buffer = ' '; | ||
| 291 | ++buffer; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | *buffer = 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 298 | (void)animation; | ||
| 299 | const char* layer_help = "1=On D=Default B=Both"; | ||
| 300 | char layer_buffer[16 + 4]; // 3 spaces and one null terminator | ||
| 301 | gdispClear(White); | ||
| 302 | gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black); | ||
| 303 | format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer); | ||
| 304 | gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black); | ||
| 305 | format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer); | ||
| 306 | gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black); | ||
| 307 | gdispFlush(); | ||
| 308 | return false; | ||
| 309 | } | ||
| 310 | #endif // LCD_ENABLE | ||
| 311 | |||
| 312 | bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 313 | (void)animation; | ||
| 314 | (void)state; | ||
| 315 | #ifdef LCD_ENABLE | ||
| 316 | gdispSetPowerMode(powerOff); | ||
| 317 | #endif | ||
| 318 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 319 | lcd_backlight_hal_color(0, 0, 0); | ||
| 320 | #endif | ||
| 321 | return false; | ||
| 322 | } | ||
| 323 | |||
| 324 | bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 325 | (void)animation; | ||
| 326 | (void)state; | ||
| 327 | #ifdef LCD_ENABLE | ||
| 328 | gdispSetPowerMode(powerOn); | ||
| 329 | #endif | ||
| 330 | return false; | ||
| 331 | } | ||
| 332 | |||
| 333 | bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 334 | (void)animation; | ||
| 335 | (void)state; | ||
| 336 | dprint("User visualizer inited\n"); | ||
| 337 | visualizer_enabled = true; | ||
| 338 | return false; | ||
| 339 | } | ||
| 340 | |||
| 341 | // TODO: Optimize the stack size, this is probably way too big | ||
| 342 | static DECLARE_THREAD_STACK(visualizerThreadStack, 1024); | ||
| 343 | static DECLARE_THREAD_FUNCTION(visualizerThread, arg) { | ||
| 344 | (void)arg; | ||
| 345 | |||
| 346 | GListener event_listener; | ||
| 347 | geventListenerInit(&event_listener); | ||
| 348 | geventAttachSource(&event_listener, (GSourceHandle)¤t_status, 0); | ||
| 349 | |||
| 350 | visualizer_keyboard_status_t initial_status = { | ||
| 351 | .default_layer = 0xFFFFFFFF, | ||
| 352 | .layer = 0xFFFFFFFF, | ||
| 353 | .leds = 0xFFFFFFFF, | ||
| 354 | .suspended = false, | ||
| 355 | }; | ||
| 356 | |||
| 357 | visualizer_state_t state = { | ||
| 358 | .status = initial_status, | ||
| 359 | .current_lcd_color = 0, | ||
| 360 | #ifdef LCD_ENABLE | ||
| 361 | .font_fixed5x8 = gdispOpenFont("fixed_5x8"), | ||
| 362 | .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12") | ||
| 363 | #endif | ||
| 364 | }; | ||
| 365 | initialize_user_visualizer(&state); | ||
| 366 | state.prev_lcd_color = state.current_lcd_color; | ||
| 367 | |||
| 368 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 369 | lcd_backlight_color( | ||
| 370 | LCD_HUE(state.current_lcd_color), | ||
| 371 | LCD_SAT(state.current_lcd_color), | ||
| 372 | LCD_INT(state.current_lcd_color)); | ||
| 373 | #endif | ||
| 374 | |||
| 375 | systemticks_t sleep_time = TIME_INFINITE; | ||
| 376 | systemticks_t current_time = gfxSystemTicks(); | ||
| 377 | |||
| 378 | while(true) { | ||
| 379 | systemticks_t new_time = gfxSystemTicks(); | ||
| 380 | systemticks_t delta = new_time - current_time; | ||
| 381 | current_time = new_time; | ||
| 382 | bool enabled = visualizer_enabled; | ||
| 383 | if (!same_status(&state.status, ¤t_status)) { | ||
| 384 | if (visualizer_enabled) { | ||
| 385 | if (current_status.suspended) { | ||
| 386 | stop_all_keyframe_animations(); | ||
| 387 | visualizer_enabled = false; | ||
| 388 | state.status = current_status; | ||
| 389 | user_visualizer_suspend(&state); | ||
| 390 | } | ||
| 391 | else { | ||
| 392 | state.status = current_status; | ||
| 393 | update_user_visualizer_state(&state); | ||
| 394 | } | ||
| 395 | state.prev_lcd_color = state.current_lcd_color; | ||
| 396 | } | ||
| 397 | } | ||
| 398 | if (!enabled && state.status.suspended && current_status.suspended == false) { | ||
| 399 | // Setting the status to the initial status will force an update | ||
| 400 | // when the visualizer is enabled again | ||
| 401 | state.status = initial_status; | ||
| 402 | state.status.suspended = false; | ||
| 403 | stop_all_keyframe_animations(); | ||
| 404 | user_visualizer_resume(&state); | ||
| 405 | state.prev_lcd_color = state.current_lcd_color; | ||
| 406 | } | ||
| 407 | sleep_time = TIME_INFINITE; | ||
| 408 | for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) { | ||
| 409 | if (animations[i]) { | ||
| 410 | update_keyframe_animation(animations[i], &state, delta, &sleep_time); | ||
| 411 | } | ||
| 412 | } | ||
| 413 | #ifdef LED_ENABLE | ||
| 414 | gdispGFlush(LED_DISPLAY); | ||
| 415 | #endif | ||
| 416 | |||
| 417 | #ifdef EMULATOR | ||
| 418 | draw_emulator(); | ||
| 419 | #endif | ||
| 420 | // The animation can enable the visualizer | ||
| 421 | // And we might need to update the state when that happens | ||
| 422 | // so don't sleep | ||
| 423 | if (enabled != visualizer_enabled) { | ||
| 424 | sleep_time = 0; | ||
| 425 | } | ||
| 426 | |||
| 427 | systemticks_t after_update = gfxSystemTicks(); | ||
| 428 | unsigned update_delta = after_update - current_time; | ||
| 429 | if (sleep_time != TIME_INFINITE) { | ||
| 430 | if (sleep_time > update_delta) { | ||
| 431 | sleep_time -= update_delta; | ||
| 432 | } | ||
| 433 | else { | ||
| 434 | sleep_time = 0; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time); | ||
| 438 | #ifdef PROTOCOL_CHIBIOS | ||
| 439 | // The gEventWait function really takes milliseconds, even if the documentation says ticks. | ||
| 440 | // Unfortunately there's no generic ugfx conversion from system time to milliseconds, | ||
| 441 | // so let's do it in a platform dependent way. | ||
| 442 | |||
| 443 | // On windows the system ticks is the same as milliseconds anyway | ||
| 444 | if (sleep_time != TIME_INFINITE) { | ||
| 445 | sleep_time = ST2MS(sleep_time); | ||
| 446 | } | ||
| 447 | #endif | ||
| 448 | geventEventWait(&event_listener, sleep_time); | ||
| 449 | } | ||
| 450 | #ifdef LCD_ENABLE | ||
| 451 | gdispCloseFont(state.font_fixed5x8); | ||
| 452 | gdispCloseFont(state.font_dejavusansbold12); | ||
| 453 | #endif | ||
| 454 | |||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | void visualizer_init(void) { | ||
| 459 | gfxInit(); | ||
| 460 | |||
| 461 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 462 | lcd_backlight_init(); | ||
| 463 | #endif | ||
| 464 | |||
| 465 | #ifdef SERIAL_LINK_ENABLE | ||
| 466 | add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) ); | ||
| 467 | #endif | ||
| 468 | |||
| 469 | #ifdef LCD_ENABLE | ||
| 470 | LCD_DISPLAY = get_lcd_display(); | ||
| 471 | #endif | ||
| 472 | #ifdef LED_ENABLE | ||
| 473 | LED_DISPLAY = get_led_display(); | ||
| 474 | #endif | ||
| 475 | |||
| 476 | // We are using a low priority thread, the idea is to have it run only | ||
| 477 | // when the main thread is sleeping during the matrix scanning | ||
| 478 | gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack), | ||
| 479 | VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL); | ||
| 480 | } | ||
| 481 | |||
| 482 | void update_status(bool changed) { | ||
| 483 | if (changed) { | ||
| 484 | GSourceListener* listener = geventGetSourceListener((GSourceHandle)¤t_status, NULL); | ||
| 485 | if (listener) { | ||
| 486 | geventSendEvent(listener); | ||
| 487 | } | ||
| 488 | } | ||
| 489 | #ifdef SERIAL_LINK_ENABLE | ||
| 490 | static systime_t last_update = 0; | ||
| 491 | systime_t current_update = chVTGetSystemTimeX(); | ||
| 492 | systime_t delta = current_update - last_update; | ||
| 493 | if (changed || delta > MS2ST(10)) { | ||
| 494 | last_update = current_update; | ||
| 495 | visualizer_keyboard_status_t* r = begin_write_current_status(); | ||
| 496 | *r = current_status; | ||
| 497 | end_write_current_status(); | ||
| 498 | } | ||
| 499 | #endif | ||
| 500 | } | ||
| 501 | |||
| 502 | void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) { | ||
| 503 | // Note that there's a small race condition here, the thread could read | ||
| 504 | // a state where one of these are set but not the other. But this should | ||
| 505 | // not really matter as it will be fixed during the next loop step. | ||
| 506 | // Alternatively a mutex could be used instead of the volatile variables | ||
| 507 | |||
| 508 | bool changed = false; | ||
| 509 | #ifdef SERIAL_LINK_ENABLE | ||
| 510 | if (is_serial_link_connected ()) { | ||
| 511 | visualizer_keyboard_status_t* new_status = read_current_status(); | ||
| 512 | if (new_status) { | ||
| 513 | if (!same_status(¤t_status, new_status)) { | ||
| 514 | changed = true; | ||
| 515 | current_status = *new_status; | ||
| 516 | } | ||
| 517 | } | ||
| 518 | } | ||
| 519 | else { | ||
| 520 | #else | ||
| 521 | { | ||
| 522 | #endif | ||
| 523 | visualizer_keyboard_status_t new_status = { | ||
| 524 | .layer = state, | ||
| 525 | .default_layer = default_state, | ||
| 526 | .leds = leds, | ||
| 527 | .suspended = current_status.suspended, | ||
| 528 | }; | ||
| 529 | if (!same_status(¤t_status, &new_status)) { | ||
| 530 | changed = true; | ||
| 531 | current_status = new_status; | ||
| 532 | } | ||
| 533 | } | ||
| 534 | update_status(changed); | ||
| 535 | } | ||
| 536 | |||
| 537 | void visualizer_suspend(void) { | ||
| 538 | current_status.suspended = true; | ||
| 539 | update_status(true); | ||
| 540 | } | ||
| 541 | |||
| 542 | void visualizer_resume(void) { | ||
| 543 | current_status.suspended = false; | ||
| 544 | update_status(true); | ||
| 545 | } | ||
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h new file mode 100644 index 000000000..53e250725 --- /dev/null +++ b/quantum/visualizer/visualizer.h | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | /* | ||
| 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 | #include "gfx.h" | ||
| 32 | |||
| 33 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 34 | #include "lcd_backlight.h" | ||
| 35 | #endif | ||
| 36 | |||
| 37 | // This need to be called once at the start | ||
| 38 | void visualizer_init(void); | ||
| 39 | // This should be called at every matrix scan | ||
| 40 | void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds); | ||
| 41 | // This should be called when the keyboard goes to suspend state | ||
| 42 | void visualizer_suspend(void); | ||
| 43 | // This should be called when the keyboard wakes up from suspend state | ||
| 44 | void visualizer_resume(void); | ||
| 45 | |||
| 46 | // These functions are week, so they can be overridden by the keyboard | ||
| 47 | // if needed | ||
| 48 | GDisplay* get_lcd_display(void); | ||
| 49 | GDisplay* get_led_display(void); | ||
| 50 | |||
| 51 | // For emulator builds, this function need to be implemented | ||
| 52 | #ifdef EMULATOR | ||
| 53 | void draw_emulator(void); | ||
| 54 | #endif | ||
| 55 | |||
| 56 | // If you need support for more than 16 keyframes per animation, you can change this | ||
| 57 | #define MAX_VISUALIZER_KEY_FRAMES 16 | ||
| 58 | |||
| 59 | struct keyframe_animation_t; | ||
| 60 | |||
| 61 | typedef struct { | ||
| 62 | uint32_t layer; | ||
| 63 | uint32_t default_layer; | ||
| 64 | uint32_t leds; // See led.h for available statuses | ||
| 65 | bool suspended; | ||
| 66 | } visualizer_keyboard_status_t; | ||
| 67 | |||
| 68 | // The state struct is used by the various keyframe functions | ||
| 69 | // It's also used for setting the LCD color and layer text | ||
| 70 | // from the user customized code | ||
| 71 | typedef struct visualizer_state_t { | ||
| 72 | // The user code should primarily be modifying these | ||
| 73 | uint32_t target_lcd_color; | ||
| 74 | const char* layer_text; | ||
| 75 | |||
| 76 | // The user visualizer(and animation functions) can read these | ||
| 77 | visualizer_keyboard_status_t status; | ||
| 78 | |||
| 79 | // These are used by the animation functions | ||
| 80 | uint32_t current_lcd_color; | ||
| 81 | uint32_t prev_lcd_color; | ||
| 82 | #ifdef LCD_ENABLE | ||
| 83 | font_t font_fixed5x8; | ||
| 84 | font_t font_dejavusansbold12; | ||
| 85 | #endif | ||
| 86 | } visualizer_state_t; | ||
| 87 | |||
| 88 | // Any custom keyframe function should have this signature | ||
| 89 | // return true to get continuous updates, otherwise you will only get one | ||
| 90 | // update per frame | ||
| 91 | typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*); | ||
| 92 | |||
| 93 | // Represents a keyframe animation, so fields are internal to the system | ||
| 94 | // while others are meant to be initialized by the user code | ||
| 95 | typedef struct keyframe_animation_t { | ||
| 96 | // These should be initialized | ||
| 97 | int num_frames; | ||
| 98 | bool loop; | ||
| 99 | int frame_lengths[MAX_VISUALIZER_KEY_FRAMES]; | ||
| 100 | frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES]; | ||
| 101 | |||
| 102 | // Used internally by the system, and can also be read by | ||
| 103 | // keyframe update functions | ||
| 104 | int current_frame; | ||
| 105 | int time_left_in_frame; | ||
| 106 | bool first_update_of_frame; | ||
| 107 | bool last_update_of_frame; | ||
| 108 | bool need_update; | ||
| 109 | |||
| 110 | } keyframe_animation_t; | ||
| 111 | |||
| 112 | extern GDisplay* LCD_DISPLAY; | ||
| 113 | extern GDisplay* LED_DISPLAY; | ||
| 114 | |||
| 115 | void start_keyframe_animation(keyframe_animation_t* animation); | ||
| 116 | void stop_keyframe_animation(keyframe_animation_t* animation); | ||
| 117 | // This runs the next keyframe, but does not update the animation state | ||
| 118 | // Useful for crossfades for example | ||
| 119 | void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 120 | |||
| 121 | // Some predefined keyframe functions that can be used by the user code | ||
| 122 | // Does nothing, useful for adding delays | ||
| 123 | bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 124 | // Animates the LCD backlight color between the current color and the target color (of the state) | ||
| 125 | bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 126 | // Sets the backlight color to the target color | ||
| 127 | bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 128 | // Displays the layer text centered vertically on the screen | ||
| 129 | bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 130 | // Displays a bitmap (0/1) of all the currently active layers | ||
| 131 | bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 132 | |||
| 133 | bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 134 | bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 135 | |||
| 136 | // Call this once, when the initial animation has finished, alternatively you can call it | ||
| 137 | // directly from the initalize_user_visualizer function (the animation can be null) | ||
| 138 | bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 139 | |||
| 140 | // These functions have to be implemented by the user | ||
| 141 | void initialize_user_visualizer(visualizer_state_t* state); | ||
| 142 | void update_user_visualizer_state(visualizer_state_t* state); | ||
| 143 | void user_visualizer_suspend(visualizer_state_t* state); | ||
| 144 | void user_visualizer_resume(visualizer_state_t* state); | ||
| 145 | |||
| 146 | |||
| 147 | #endif /* VISUALIZER_H */ | ||
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk new file mode 100644 index 000000000..2f4a41d66 --- /dev/null +++ b/quantum/visualizer/visualizer.mk | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | # The MIT License (MIT) | ||
| 2 | # | ||
| 3 | # Copyright (c) 2016 Fred Sundvik | ||
| 4 | # | ||
| 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | # of this software and associated documentation files (the "Software"), to deal | ||
| 7 | # in the Software without restriction, including without limitation the rights | ||
| 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | # copies of the Software, and to permit persons to whom the Software is | ||
| 10 | # furnished to do so, subject to the following conditions: | ||
| 11 | # | ||
| 12 | # The above copyright notice and this permission notice shall be included in all | ||
| 13 | # copies or substantial portions of the Software. | ||
| 14 | # | ||
| 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | # SOFTWARE. | ||
| 22 | |||
| 23 | SRC += $(VISUALIZER_DIR)/visualizer.c | ||
| 24 | EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR) | ||
| 25 | GFXLIB = $(LIB_PATH)/ugfx | ||
| 26 | VPATH += $(VISUALIZER_PATH) | ||
| 27 | |||
| 28 | OPT_DEFS += -DVISUALIZER_ENABLE | ||
| 29 | |||
| 30 | ifdef LCD_ENABLE | ||
| 31 | OPT_DEFS += -DLCD_ENABLE | ||
| 32 | ULIBS += -lm | ||
| 33 | endif | ||
| 34 | |||
| 35 | ifdef LCD_BACKLIGHT_ENABLE | ||
| 36 | SRC += $(VISUALIZER_DIR)/lcd_backlight.c | ||
| 37 | OPT_DEFS += -DLCD_BACKLIGHT_ENABLE | ||
| 38 | endif | ||
| 39 | |||
| 40 | ifdef LED_ENABLE | ||
| 41 | SRC += $(VISUALIZER_DIR)/led_test.c | ||
| 42 | OPT_DEFS += -DLED_ENABLE | ||
| 43 | endif | ||
| 44 | |||
| 45 | include $(GFXLIB)/gfx.mk | ||
| 46 | SRC += $(patsubst $(TOP_DIR)/%,%,$(GFXSRC)) | ||
| 47 | OPT_DEFS += $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS))) | ||
| 48 | |||
| 49 | ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","") | ||
| 50 | SRC += keyboards/$(KEYBOARD)/keymaps/$(KEYMAP)/visualizer.c | ||
| 51 | else | ||
| 52 | ifeq ("$(wildcard $(SUBPROJECT_PATH)/keymaps/$(KEYMAP)/visualizer.c)","") | ||
| 53 | $(error "$(KEYMAP_PATH)/visualizer.c" does not exist) | ||
| 54 | else | ||
| 55 | SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/keymaps/$(KEYMAP)/visualizer.c | ||
| 56 | endif | ||
| 57 | endif | ||
| 58 | |||
| 59 | ifdef EMULATOR | ||
| 60 | UINCDIR += $(TMK_DIR)/common | ||
| 61 | endif \ No newline at end of file | ||
