diff options
Diffstat (limited to 'quantum')
90 files changed, 10340 insertions, 0 deletions
diff --git a/quantum/analog.c b/quantum/analog.c new file mode 100644 index 000000000..49b84ee0e --- /dev/null +++ b/quantum/analog.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // Simple analog to digitial conversion | ||
| 2 | |||
| 3 | #include <avr/io.h> | ||
| 4 | #include <avr/pgmspace.h> | ||
| 5 | #include <stdint.h> | ||
| 6 | #include "analog.h" | ||
| 7 | |||
| 8 | |||
| 9 | static uint8_t aref = (1<<REFS0); // default to AREF = Vcc | ||
| 10 | |||
| 11 | |||
| 12 | void analogReference(uint8_t mode) | ||
| 13 | { | ||
| 14 | aref = mode & 0xC0; | ||
| 15 | } | ||
| 16 | |||
| 17 | |||
| 18 | // Arduino compatible pin input | ||
| 19 | int16_t analogRead(uint8_t pin) | ||
| 20 | { | ||
| 21 | #if defined(__AVR_ATmega32U4__) | ||
| 22 | static const uint8_t PROGMEM pin_to_mux[] = { | ||
| 23 | 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, | ||
| 24 | 0x25, 0x24, 0x23, 0x22, 0x21, 0x20}; | ||
| 25 | if (pin >= 12) return 0; | ||
| 26 | return adc_read(pgm_read_byte(pin_to_mux + pin)); | ||
| 27 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | ||
| 28 | if (pin >= 8) return 0; | ||
| 29 | return adc_read(pin); | ||
| 30 | #else | ||
| 31 | return 0; | ||
| 32 | #endif | ||
| 33 | } | ||
| 34 | |||
| 35 | // Mux input | ||
| 36 | int16_t adc_read(uint8_t mux) | ||
| 37 | { | ||
| 38 | #if defined(__AVR_AT90USB162__) | ||
| 39 | return 0; | ||
| 40 | #else | ||
| 41 | uint8_t low; | ||
| 42 | |||
| 43 | ADCSRA = (1<<ADEN) | ADC_PRESCALER; // enable ADC | ||
| 44 | ADCSRB = (1<<ADHSM) | (mux & 0x20); // high speed mode | ||
| 45 | ADMUX = aref | (mux & 0x1F); // configure mux input | ||
| 46 | ADCSRA = (1<<ADEN) | ADC_PRESCALER | (1<<ADSC); // start the conversion | ||
| 47 | while (ADCSRA & (1<<ADSC)) ; // wait for result | ||
| 48 | low = ADCL; // must read LSB first | ||
| 49 | return (ADCH << 8) | low; // must read MSB only once! | ||
| 50 | #endif | ||
| 51 | } | ||
| 52 | |||
| 53 | |||
diff --git a/quantum/analog.h b/quantum/analog.h new file mode 100644 index 000000000..9b95a93be --- /dev/null +++ b/quantum/analog.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #ifndef _analog_h_included__ | ||
| 2 | #define _analog_h_included__ | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | |||
| 6 | void analogReference(uint8_t mode); | ||
| 7 | int16_t analogRead(uint8_t pin); | ||
| 8 | int16_t adc_read(uint8_t mux); | ||
| 9 | |||
| 10 | #define ADC_REF_POWER (1<<REFS0) | ||
| 11 | #define ADC_REF_INTERNAL ((1<<REFS1) | (1<<REFS0)) | ||
| 12 | #define ADC_REF_EXTERNAL (0) | ||
| 13 | |||
| 14 | // These prescaler values are for high speed mode, ADHSM = 1 | ||
| 15 | #if F_CPU == 16000000L | ||
| 16 | #define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS1)) | ||
| 17 | #elif F_CPU == 8000000L | ||
| 18 | #define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS0)) | ||
| 19 | #elif F_CPU == 4000000L | ||
| 20 | #define ADC_PRESCALER ((1<<ADPS2)) | ||
| 21 | #elif F_CPU == 2000000L | ||
| 22 | #define ADC_PRESCALER ((1<<ADPS1) | (1<<ADPS0)) | ||
| 23 | #elif F_CPU == 1000000L | ||
| 24 | #define ADC_PRESCALER ((1<<ADPS1)) | ||
| 25 | #else | ||
| 26 | #define ADC_PRESCALER ((1<<ADPS0)) | ||
| 27 | #endif | ||
| 28 | |||
| 29 | // some avr-libc versions do not properly define ADHSM | ||
| 30 | #if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | ||
| 31 | #if !defined(ADHSM) | ||
| 32 | #define ADHSM (7) | ||
| 33 | #endif | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #endif | ||
diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c new file mode 100644 index 000000000..ead5fbf3e --- /dev/null +++ b/quantum/audio/audio.c | |||
| @@ -0,0 +1,477 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | //#include <math.h> | ||
| 4 | #include <avr/pgmspace.h> | ||
| 5 | #include <avr/interrupt.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | #include "print.h" | ||
| 8 | #include "audio.h" | ||
| 9 | #include "keymap.h" | ||
| 10 | |||
| 11 | #include "eeconfig.h" | ||
| 12 | |||
| 13 | #define CPU_PRESCALER 8 | ||
| 14 | |||
| 15 | // ----------------------------------------------------------------------------- | ||
| 16 | // Timer Abstractions | ||
| 17 | // ----------------------------------------------------------------------------- | ||
| 18 | |||
| 19 | // TIMSK3 - Timer/Counter #3 Interrupt Mask Register | ||
| 20 | // Turn on/off 3A interputs, stopping/enabling the ISR calls | ||
| 21 | #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) | ||
| 22 | #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) | ||
| 23 | |||
| 24 | // TCCR3A: Timer/Counter #3 Control Register | ||
| 25 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | ||
| 26 | #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); | ||
| 27 | #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); | ||
| 28 | |||
| 29 | // Fast PWM Mode Controls | ||
| 30 | #define TIMER_3_PERIOD ICR3 | ||
| 31 | #define TIMER_3_DUTY_CYCLE OCR3A | ||
| 32 | |||
| 33 | // ----------------------------------------------------------------------------- | ||
| 34 | |||
| 35 | |||
| 36 | int voices = 0; | ||
| 37 | int voice_place = 0; | ||
| 38 | float frequency = 0; | ||
| 39 | int volume = 0; | ||
| 40 | long position = 0; | ||
| 41 | |||
| 42 | float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 43 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 44 | bool sliding = false; | ||
| 45 | |||
| 46 | float place = 0; | ||
| 47 | |||
| 48 | uint8_t * sample; | ||
| 49 | uint16_t sample_length = 0; | ||
| 50 | |||
| 51 | bool playing_notes = false; | ||
| 52 | bool playing_note = false; | ||
| 53 | float note_frequency = 0; | ||
| 54 | float note_length = 0; | ||
| 55 | uint8_t note_tempo = TEMPO_DEFAULT; | ||
| 56 | float note_timbre = TIMBRE_DEFAULT; | ||
| 57 | uint16_t note_position = 0; | ||
| 58 | float (* notes_pointer)[][2]; | ||
| 59 | uint16_t notes_count; | ||
| 60 | bool notes_repeat; | ||
| 61 | float notes_rest; | ||
| 62 | bool note_resting = false; | ||
| 63 | |||
| 64 | uint8_t current_note = 0; | ||
| 65 | uint8_t rest_counter = 0; | ||
| 66 | |||
| 67 | #ifdef VIBRATO_ENABLE | ||
| 68 | float vibrato_counter = 0; | ||
| 69 | float vibrato_strength = .5; | ||
| 70 | float vibrato_rate = 0.125; | ||
| 71 | #endif | ||
| 72 | |||
| 73 | float polyphony_rate = 0; | ||
| 74 | |||
| 75 | static bool audio_initialized = false; | ||
| 76 | |||
| 77 | audio_config_t audio_config; | ||
| 78 | |||
| 79 | uint16_t envelope_index = 0; | ||
| 80 | |||
| 81 | void audio_init() | ||
| 82 | { | ||
| 83 | |||
| 84 | // Check EEPROM | ||
| 85 | if (!eeconfig_is_enabled()) | ||
| 86 | { | ||
| 87 | eeconfig_init(); | ||
| 88 | } | ||
| 89 | audio_config.raw = eeconfig_read_audio(); | ||
| 90 | |||
| 91 | // Set port PC6 (OC3A and /OC4A) as output | ||
| 92 | DDRC |= _BV(PORTC6); | ||
| 93 | |||
| 94 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 95 | |||
| 96 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers | ||
| 97 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | ||
| 98 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) | ||
| 99 | // Clock Select (CS3n) = 0b010 = Clock / 8 | ||
| 100 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||
| 101 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | ||
| 102 | |||
| 103 | audio_initialized = true; | ||
| 104 | } | ||
| 105 | |||
| 106 | void stop_all_notes() | ||
| 107 | { | ||
| 108 | if (!audio_initialized) { | ||
| 109 | audio_init(); | ||
| 110 | } | ||
| 111 | voices = 0; | ||
| 112 | |||
| 113 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 114 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 115 | |||
| 116 | playing_notes = false; | ||
| 117 | playing_note = false; | ||
| 118 | frequency = 0; | ||
| 119 | volume = 0; | ||
| 120 | |||
| 121 | for (uint8_t i = 0; i < 8; i++) | ||
| 122 | { | ||
| 123 | frequencies[i] = 0; | ||
| 124 | volumes[i] = 0; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | void stop_note(float freq) | ||
| 129 | { | ||
| 130 | if (playing_note) { | ||
| 131 | if (!audio_initialized) { | ||
| 132 | audio_init(); | ||
| 133 | } | ||
| 134 | for (int i = 7; i >= 0; i--) { | ||
| 135 | if (frequencies[i] == freq) { | ||
| 136 | frequencies[i] = 0; | ||
| 137 | volumes[i] = 0; | ||
| 138 | for (int j = i; (j < 7); j++) { | ||
| 139 | frequencies[j] = frequencies[j+1]; | ||
| 140 | frequencies[j+1] = 0; | ||
| 141 | volumes[j] = volumes[j+1]; | ||
| 142 | volumes[j+1] = 0; | ||
| 143 | } | ||
| 144 | break; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | voices--; | ||
| 148 | if (voices < 0) | ||
| 149 | voices = 0; | ||
| 150 | if (voice_place >= voices) { | ||
| 151 | voice_place = 0; | ||
| 152 | } | ||
| 153 | if (voices == 0) { | ||
| 154 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 155 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 156 | frequency = 0; | ||
| 157 | volume = 0; | ||
| 158 | playing_note = false; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | #ifdef VIBRATO_ENABLE | ||
| 164 | |||
| 165 | float mod(float a, int b) | ||
| 166 | { | ||
| 167 | float r = fmod(a, b); | ||
| 168 | return r < 0 ? r + b : r; | ||
| 169 | } | ||
| 170 | |||
| 171 | float vibrato(float average_freq) { | ||
| 172 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
| 173 | float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); | ||
| 174 | #else | ||
| 175 | float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; | ||
| 176 | #endif | ||
| 177 | vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); | ||
| 178 | return vibrated_freq; | ||
| 179 | } | ||
| 180 | |||
| 181 | #endif | ||
| 182 | |||
| 183 | ISR(TIMER3_COMPA_vect) | ||
| 184 | { | ||
| 185 | float freq; | ||
| 186 | |||
| 187 | if (playing_note) { | ||
| 188 | if (voices > 0) { | ||
| 189 | if (polyphony_rate > 0) { | ||
| 190 | if (voices > 1) { | ||
| 191 | voice_place %= voices; | ||
| 192 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||
| 193 | voice_place = (voice_place + 1) % voices; | ||
| 194 | place = 0.0; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | #ifdef VIBRATO_ENABLE | ||
| 199 | if (vibrato_strength > 0) { | ||
| 200 | freq = vibrato(frequencies[voice_place]); | ||
| 201 | } else { | ||
| 202 | freq = frequencies[voice_place]; | ||
| 203 | } | ||
| 204 | #else | ||
| 205 | freq = frequencies[voice_place]; | ||
| 206 | #endif | ||
| 207 | } else { | ||
| 208 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | ||
| 209 | frequency = frequency * pow(2, 440/frequency/12/2); | ||
| 210 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | ||
| 211 | frequency = frequency * pow(2, -440/frequency/12/2); | ||
| 212 | } else { | ||
| 213 | frequency = frequencies[voices - 1]; | ||
| 214 | } | ||
| 215 | |||
| 216 | #ifdef VIBRATO_ENABLE | ||
| 217 | if (vibrato_strength > 0) { | ||
| 218 | freq = vibrato(frequency); | ||
| 219 | } else { | ||
| 220 | freq = frequency; | ||
| 221 | } | ||
| 222 | #else | ||
| 223 | freq = frequency; | ||
| 224 | #endif | ||
| 225 | } | ||
| 226 | |||
| 227 | if (envelope_index < 65535) { | ||
| 228 | envelope_index++; | ||
| 229 | } | ||
| 230 | |||
| 231 | freq = voice_envelope(freq); | ||
| 232 | |||
| 233 | if (freq < 30.517578125) { | ||
| 234 | freq = 30.52; | ||
| 235 | } | ||
| 236 | |||
| 237 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
| 238 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | if (playing_notes) { | ||
| 243 | if (note_frequency > 0) { | ||
| 244 | #ifdef VIBRATO_ENABLE | ||
| 245 | if (vibrato_strength > 0) { | ||
| 246 | freq = vibrato(note_frequency); | ||
| 247 | } else { | ||
| 248 | freq = note_frequency; | ||
| 249 | } | ||
| 250 | #else | ||
| 251 | freq = note_frequency; | ||
| 252 | #endif | ||
| 253 | |||
| 254 | if (envelope_index < 65535) { | ||
| 255 | envelope_index++; | ||
| 256 | } | ||
| 257 | freq = voice_envelope(freq); | ||
| 258 | |||
| 259 | TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
| 260 | TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); | ||
| 261 | } else { | ||
| 262 | TIMER_3_PERIOD = 0; | ||
| 263 | TIMER_3_DUTY_CYCLE = 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | note_position++; | ||
| 267 | bool end_of_note = false; | ||
| 268 | if (TIMER_3_PERIOD > 0) { | ||
| 269 | end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); | ||
| 270 | } else { | ||
| 271 | end_of_note = (note_position >= (note_length * 0x7FF)); | ||
| 272 | } | ||
| 273 | |||
| 274 | if (end_of_note) { | ||
| 275 | current_note++; | ||
| 276 | if (current_note >= notes_count) { | ||
| 277 | if (notes_repeat) { | ||
| 278 | current_note = 0; | ||
| 279 | } else { | ||
| 280 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 281 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 282 | playing_notes = false; | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | if (!note_resting && (notes_rest > 0)) { | ||
| 287 | note_resting = true; | ||
| 288 | note_frequency = 0; | ||
| 289 | note_length = notes_rest; | ||
| 290 | current_note--; | ||
| 291 | } else { | ||
| 292 | note_resting = false; | ||
| 293 | envelope_index = 0; | ||
| 294 | note_frequency = (*notes_pointer)[current_note][0]; | ||
| 295 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
| 296 | } | ||
| 297 | |||
| 298 | note_position = 0; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | if (!audio_config.enable) { | ||
| 303 | playing_notes = false; | ||
| 304 | playing_note = false; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | void play_note(float freq, int vol) { | ||
| 309 | |||
| 310 | if (!audio_initialized) { | ||
| 311 | audio_init(); | ||
| 312 | } | ||
| 313 | |||
| 314 | if (audio_config.enable && voices < 8) { | ||
| 315 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 316 | |||
| 317 | // Cancel notes if notes are playing | ||
| 318 | if (playing_notes) | ||
| 319 | stop_all_notes(); | ||
| 320 | |||
| 321 | playing_note = true; | ||
| 322 | |||
| 323 | envelope_index = 0; | ||
| 324 | |||
| 325 | if (freq > 0) { | ||
| 326 | frequencies[voices] = freq; | ||
| 327 | volumes[voices] = vol; | ||
| 328 | voices++; | ||
| 329 | } | ||
| 330 | |||
| 331 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 332 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 333 | } | ||
| 334 | |||
| 335 | } | ||
| 336 | |||
| 337 | void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | ||
| 338 | { | ||
| 339 | |||
| 340 | if (!audio_initialized) { | ||
| 341 | audio_init(); | ||
| 342 | } | ||
| 343 | |||
| 344 | if (audio_config.enable) { | ||
| 345 | |||
| 346 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 347 | |||
| 348 | // Cancel note if a note is playing | ||
| 349 | if (playing_note) | ||
| 350 | stop_all_notes(); | ||
| 351 | |||
| 352 | playing_notes = true; | ||
| 353 | |||
| 354 | notes_pointer = np; | ||
| 355 | notes_count = n_count; | ||
| 356 | notes_repeat = n_repeat; | ||
| 357 | notes_rest = n_rest; | ||
| 358 | |||
| 359 | place = 0; | ||
| 360 | current_note = 0; | ||
| 361 | |||
| 362 | note_frequency = (*notes_pointer)[current_note][0]; | ||
| 363 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
| 364 | note_position = 0; | ||
| 365 | |||
| 366 | |||
| 367 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 368 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 369 | } | ||
| 370 | |||
| 371 | } | ||
| 372 | |||
| 373 | bool is_playing_notes(void) { | ||
| 374 | return playing_notes; | ||
| 375 | } | ||
| 376 | |||
| 377 | bool is_audio_on(void) { | ||
| 378 | return (audio_config.enable != 0); | ||
| 379 | } | ||
| 380 | |||
| 381 | void audio_toggle(void) { | ||
| 382 | audio_config.enable ^= 1; | ||
| 383 | eeconfig_update_audio(audio_config.raw); | ||
| 384 | if (audio_config.enable) | ||
| 385 | audio_on_user(); | ||
| 386 | } | ||
| 387 | |||
| 388 | void audio_on(void) { | ||
| 389 | audio_config.enable = 1; | ||
| 390 | eeconfig_update_audio(audio_config.raw); | ||
| 391 | audio_on_user(); | ||
| 392 | } | ||
| 393 | |||
| 394 | void audio_off(void) { | ||
| 395 | audio_config.enable = 0; | ||
| 396 | eeconfig_update_audio(audio_config.raw); | ||
| 397 | } | ||
| 398 | |||
| 399 | #ifdef VIBRATO_ENABLE | ||
| 400 | |||
| 401 | // Vibrato rate functions | ||
| 402 | |||
| 403 | void set_vibrato_rate(float rate) { | ||
| 404 | vibrato_rate = rate; | ||
| 405 | } | ||
| 406 | |||
| 407 | void increase_vibrato_rate(float change) { | ||
| 408 | vibrato_rate *= change; | ||
| 409 | } | ||
| 410 | |||
| 411 | void decrease_vibrato_rate(float change) { | ||
| 412 | vibrato_rate /= change; | ||
| 413 | } | ||
| 414 | |||
| 415 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
| 416 | |||
| 417 | void set_vibrato_strength(float strength) { | ||
| 418 | vibrato_strength = strength; | ||
| 419 | } | ||
| 420 | |||
| 421 | void increase_vibrato_strength(float change) { | ||
| 422 | vibrato_strength *= change; | ||
| 423 | } | ||
| 424 | |||
| 425 | void decrease_vibrato_strength(float change) { | ||
| 426 | vibrato_strength /= change; | ||
| 427 | } | ||
| 428 | |||
| 429 | #endif /* VIBRATO_STRENGTH_ENABLE */ | ||
| 430 | |||
| 431 | #endif /* VIBRATO_ENABLE */ | ||
| 432 | |||
| 433 | // Polyphony functions | ||
| 434 | |||
| 435 | void set_polyphony_rate(float rate) { | ||
| 436 | polyphony_rate = rate; | ||
| 437 | } | ||
| 438 | |||
| 439 | void enable_polyphony() { | ||
| 440 | polyphony_rate = 5; | ||
| 441 | } | ||
| 442 | |||
| 443 | void disable_polyphony() { | ||
| 444 | polyphony_rate = 0; | ||
| 445 | } | ||
| 446 | |||
| 447 | void increase_polyphony_rate(float change) { | ||
| 448 | polyphony_rate *= change; | ||
| 449 | } | ||
| 450 | |||
| 451 | void decrease_polyphony_rate(float change) { | ||
| 452 | polyphony_rate /= change; | ||
| 453 | } | ||
| 454 | |||
| 455 | // Timbre function | ||
| 456 | |||
| 457 | void set_timbre(float timbre) { | ||
| 458 | note_timbre = timbre; | ||
| 459 | } | ||
| 460 | |||
| 461 | // Tempo functions | ||
| 462 | |||
| 463 | void set_tempo(uint8_t tempo) { | ||
| 464 | note_tempo = tempo; | ||
| 465 | } | ||
| 466 | |||
| 467 | void decrease_tempo(uint8_t tempo_change) { | ||
| 468 | note_tempo += tempo_change; | ||
| 469 | } | ||
| 470 | |||
| 471 | void increase_tempo(uint8_t tempo_change) { | ||
| 472 | if (note_tempo - tempo_change < 10) { | ||
| 473 | note_tempo = 10; | ||
| 474 | } else { | ||
| 475 | note_tempo -= tempo_change; | ||
| 476 | } | ||
| 477 | } | ||
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h new file mode 100644 index 000000000..47f326ea0 --- /dev/null +++ b/quantum/audio/audio.h | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | #ifndef AUDIO_H | ||
| 2 | #define AUDIO_H | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <stdbool.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | #include <util/delay.h> | ||
| 8 | #include "musical_notes.h" | ||
| 9 | #include "song_list.h" | ||
| 10 | #include "voices.h" | ||
| 11 | #include "quantum.h" | ||
| 12 | |||
| 13 | // Largely untested PWM audio mode (doesn't sound as good) | ||
| 14 | // #define PWM_AUDIO | ||
| 15 | |||
| 16 | // #define VIBRATO_ENABLE | ||
| 17 | |||
| 18 | // Enable vibrato strength/amplitude - slows down ISR too much | ||
| 19 | // #define VIBRATO_STRENGTH_ENABLE | ||
| 20 | |||
| 21 | typedef union { | ||
| 22 | uint8_t raw; | ||
| 23 | struct { | ||
| 24 | bool enable :1; | ||
| 25 | uint8_t level :7; | ||
| 26 | }; | ||
| 27 | } audio_config_t; | ||
| 28 | |||
| 29 | bool is_audio_on(void); | ||
| 30 | void audio_toggle(void); | ||
| 31 | void audio_on(void); | ||
| 32 | void audio_off(void); | ||
| 33 | |||
| 34 | // Vibrato rate functions | ||
| 35 | |||
| 36 | #ifdef VIBRATO_ENABLE | ||
| 37 | |||
| 38 | void set_vibrato_rate(float rate); | ||
| 39 | void increase_vibrato_rate(float change); | ||
| 40 | void decrease_vibrato_rate(float change); | ||
| 41 | |||
| 42 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
| 43 | |||
| 44 | void set_vibrato_strength(float strength); | ||
| 45 | void increase_vibrato_strength(float change); | ||
| 46 | void decrease_vibrato_strength(float change); | ||
| 47 | |||
| 48 | #endif | ||
| 49 | |||
| 50 | #endif | ||
| 51 | |||
| 52 | // Polyphony functions | ||
| 53 | |||
| 54 | void set_polyphony_rate(float rate); | ||
| 55 | void enable_polyphony(void); | ||
| 56 | void disable_polyphony(void); | ||
| 57 | void increase_polyphony_rate(float change); | ||
| 58 | void decrease_polyphony_rate(float change); | ||
| 59 | |||
| 60 | void set_timbre(float timbre); | ||
| 61 | void set_tempo(uint8_t tempo); | ||
| 62 | |||
| 63 | void increase_tempo(uint8_t tempo_change); | ||
| 64 | void decrease_tempo(uint8_t tempo_change); | ||
| 65 | |||
| 66 | void audio_init(void); | ||
| 67 | |||
| 68 | #ifdef PWM_AUDIO | ||
| 69 | void play_sample(uint8_t * s, uint16_t l, bool r); | ||
| 70 | #endif | ||
| 71 | void play_note(float freq, int vol); | ||
| 72 | void stop_note(float freq); | ||
| 73 | void stop_all_notes(void); | ||
| 74 | void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest); | ||
| 75 | |||
| 76 | #define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ | ||
| 77 | 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ | ||
| 78 | 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ | ||
| 79 | 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ | ||
| 80 | 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } | ||
| 81 | |||
| 82 | // These macros are used to allow play_notes to play an array of indeterminate | ||
| 83 | // length. This works around the limitation of C's sizeof operation on pointers. | ||
| 84 | // The global float array for the song must be used here. | ||
| 85 | #define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) | ||
| 86 | #define PLAY_NOTE_ARRAY(note_array, note_repeat, note_rest_style) play_notes(¬e_array, NOTE_ARRAY_SIZE((note_array)), (note_repeat), (note_rest_style)); | ||
| 87 | |||
| 88 | |||
| 89 | bool is_playing_notes(void); | ||
| 90 | |||
| 91 | #endif \ No newline at end of file | ||
diff --git a/quantum/audio/audio_pwm.c b/quantum/audio/audio_pwm.c new file mode 100644 index 000000000..f820eec1b --- /dev/null +++ b/quantum/audio/audio_pwm.c | |||
| @@ -0,0 +1,643 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <string.h> | ||
| 3 | //#include <math.h> | ||
| 4 | #include <avr/pgmspace.h> | ||
| 5 | #include <avr/interrupt.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | #include "print.h" | ||
| 8 | #include "audio.h" | ||
| 9 | #include "keymap.h" | ||
| 10 | |||
| 11 | #include "eeconfig.h" | ||
| 12 | |||
| 13 | #define PI 3.14159265 | ||
| 14 | |||
| 15 | #define CPU_PRESCALER 8 | ||
| 16 | |||
| 17 | |||
| 18 | // Timer Abstractions | ||
| 19 | |||
| 20 | // TIMSK3 - Timer/Counter #3 Interrupt Mask Register | ||
| 21 | // Turn on/off 3A interputs, stopping/enabling the ISR calls | ||
| 22 | #define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) | ||
| 23 | #define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) | ||
| 24 | |||
| 25 | |||
| 26 | // TCCR3A: Timer/Counter #3 Control Register | ||
| 27 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | ||
| 28 | #define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); | ||
| 29 | #define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); | ||
| 30 | |||
| 31 | |||
| 32 | #define NOTE_PERIOD ICR3 | ||
| 33 | #define NOTE_DUTY_CYCLE OCR3A | ||
| 34 | |||
| 35 | |||
| 36 | #ifdef PWM_AUDIO | ||
| 37 | #include "wave.h" | ||
| 38 | #define SAMPLE_DIVIDER 39 | ||
| 39 | #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048) | ||
| 40 | // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap | ||
| 41 | |||
| 42 | float places[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 43 | uint16_t place_int = 0; | ||
| 44 | bool repeat = true; | ||
| 45 | #endif | ||
| 46 | |||
| 47 | void delay_us(int count) { | ||
| 48 | while(count--) { | ||
| 49 | _delay_us(1); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | int voices = 0; | ||
| 54 | int voice_place = 0; | ||
| 55 | float frequency = 0; | ||
| 56 | int volume = 0; | ||
| 57 | long position = 0; | ||
| 58 | |||
| 59 | float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 60 | int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||
| 61 | bool sliding = false; | ||
| 62 | |||
| 63 | float place = 0; | ||
| 64 | |||
| 65 | uint8_t * sample; | ||
| 66 | uint16_t sample_length = 0; | ||
| 67 | // float freq = 0; | ||
| 68 | |||
| 69 | bool playing_notes = false; | ||
| 70 | bool playing_note = false; | ||
| 71 | float note_frequency = 0; | ||
| 72 | float note_length = 0; | ||
| 73 | uint8_t note_tempo = TEMPO_DEFAULT; | ||
| 74 | float note_timbre = TIMBRE_DEFAULT; | ||
| 75 | uint16_t note_position = 0; | ||
| 76 | float (* notes_pointer)[][2]; | ||
| 77 | uint16_t notes_count; | ||
| 78 | bool notes_repeat; | ||
| 79 | float notes_rest; | ||
| 80 | bool note_resting = false; | ||
| 81 | |||
| 82 | uint8_t current_note = 0; | ||
| 83 | uint8_t rest_counter = 0; | ||
| 84 | |||
| 85 | #ifdef VIBRATO_ENABLE | ||
| 86 | float vibrato_counter = 0; | ||
| 87 | float vibrato_strength = .5; | ||
| 88 | float vibrato_rate = 0.125; | ||
| 89 | #endif | ||
| 90 | |||
| 91 | float polyphony_rate = 0; | ||
| 92 | |||
| 93 | static bool audio_initialized = false; | ||
| 94 | |||
| 95 | audio_config_t audio_config; | ||
| 96 | |||
| 97 | uint16_t envelope_index = 0; | ||
| 98 | |||
| 99 | void audio_init() { | ||
| 100 | |||
| 101 | // Check EEPROM | ||
| 102 | if (!eeconfig_is_enabled()) | ||
| 103 | { | ||
| 104 | eeconfig_init(); | ||
| 105 | } | ||
| 106 | audio_config.raw = eeconfig_read_audio(); | ||
| 107 | |||
| 108 | #ifdef PWM_AUDIO | ||
| 109 | |||
| 110 | PLLFRQ = _BV(PDIV2); | ||
| 111 | PLLCSR = _BV(PLLE); | ||
| 112 | while(!(PLLCSR & _BV(PLOCK))); | ||
| 113 | PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */ | ||
| 114 | |||
| 115 | /* Init a fast PWM on Timer4 */ | ||
| 116 | TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */ | ||
| 117 | TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */ | ||
| 118 | OCR4A = 0; | ||
| 119 | |||
| 120 | /* Enable the OC4A output */ | ||
| 121 | DDRC |= _BV(PORTC6); | ||
| 122 | |||
| 123 | DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs | ||
| 124 | |||
| 125 | TCCR3A = 0x0; // Options not needed | ||
| 126 | TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC | ||
| 127 | OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback | ||
| 128 | |||
| 129 | #else | ||
| 130 | |||
| 131 | // Set port PC6 (OC3A and /OC4A) as output | ||
| 132 | DDRC |= _BV(PORTC6); | ||
| 133 | |||
| 134 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 135 | |||
| 136 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers | ||
| 137 | // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 | ||
| 138 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) | ||
| 139 | // Clock Select (CS3n) = 0b010 = Clock / 8 | ||
| 140 | TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); | ||
| 141 | TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); | ||
| 142 | |||
| 143 | #endif | ||
| 144 | |||
| 145 | audio_initialized = true; | ||
| 146 | } | ||
| 147 | |||
| 148 | void stop_all_notes() { | ||
| 149 | if (!audio_initialized) { | ||
| 150 | audio_init(); | ||
| 151 | } | ||
| 152 | voices = 0; | ||
| 153 | #ifdef PWM_AUDIO | ||
| 154 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 155 | #else | ||
| 156 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 157 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 158 | #endif | ||
| 159 | |||
| 160 | playing_notes = false; | ||
| 161 | playing_note = false; | ||
| 162 | frequency = 0; | ||
| 163 | volume = 0; | ||
| 164 | |||
| 165 | for (uint8_t i = 0; i < 8; i++) | ||
| 166 | { | ||
| 167 | frequencies[i] = 0; | ||
| 168 | volumes[i] = 0; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | void stop_note(float freq) | ||
| 173 | { | ||
| 174 | if (playing_note) { | ||
| 175 | if (!audio_initialized) { | ||
| 176 | audio_init(); | ||
| 177 | } | ||
| 178 | #ifdef PWM_AUDIO | ||
| 179 | freq = freq / SAMPLE_RATE; | ||
| 180 | #endif | ||
| 181 | for (int i = 7; i >= 0; i--) { | ||
| 182 | if (frequencies[i] == freq) { | ||
| 183 | frequencies[i] = 0; | ||
| 184 | volumes[i] = 0; | ||
| 185 | for (int j = i; (j < 7); j++) { | ||
| 186 | frequencies[j] = frequencies[j+1]; | ||
| 187 | frequencies[j+1] = 0; | ||
| 188 | volumes[j] = volumes[j+1]; | ||
| 189 | volumes[j+1] = 0; | ||
| 190 | } | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | voices--; | ||
| 195 | if (voices < 0) | ||
| 196 | voices = 0; | ||
| 197 | if (voice_place >= voices) { | ||
| 198 | voice_place = 0; | ||
| 199 | } | ||
| 200 | if (voices == 0) { | ||
| 201 | #ifdef PWM_AUDIO | ||
| 202 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 203 | #else | ||
| 204 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 205 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 206 | #endif | ||
| 207 | frequency = 0; | ||
| 208 | volume = 0; | ||
| 209 | playing_note = false; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | #ifdef VIBRATO_ENABLE | ||
| 215 | |||
| 216 | float mod(float a, int b) | ||
| 217 | { | ||
| 218 | float r = fmod(a, b); | ||
| 219 | return r < 0 ? r + b : r; | ||
| 220 | } | ||
| 221 | |||
| 222 | float vibrato(float average_freq) { | ||
| 223 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
| 224 | float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); | ||
| 225 | #else | ||
| 226 | float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; | ||
| 227 | #endif | ||
| 228 | vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); | ||
| 229 | return vibrated_freq; | ||
| 230 | } | ||
| 231 | |||
| 232 | #endif | ||
| 233 | |||
| 234 | ISR(TIMER3_COMPA_vect) | ||
| 235 | { | ||
| 236 | if (playing_note) { | ||
| 237 | #ifdef PWM_AUDIO | ||
| 238 | if (voices == 1) { | ||
| 239 | // SINE | ||
| 240 | OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2; | ||
| 241 | |||
| 242 | // SQUARE | ||
| 243 | // if (((int)place) >= 1024){ | ||
| 244 | // OCR4A = 0xFF >> 2; | ||
| 245 | // } else { | ||
| 246 | // OCR4A = 0x00; | ||
| 247 | // } | ||
| 248 | |||
| 249 | // SAWTOOTH | ||
| 250 | // OCR4A = (int)place / 4; | ||
| 251 | |||
| 252 | // TRIANGLE | ||
| 253 | // if (((int)place) >= 1024) { | ||
| 254 | // OCR4A = (int)place / 2; | ||
| 255 | // } else { | ||
| 256 | // OCR4A = 2048 - (int)place / 2; | ||
| 257 | // } | ||
| 258 | |||
| 259 | place += frequency; | ||
| 260 | |||
| 261 | if (place >= SINE_LENGTH) | ||
| 262 | place -= SINE_LENGTH; | ||
| 263 | |||
| 264 | } else { | ||
| 265 | int sum = 0; | ||
| 266 | for (int i = 0; i < voices; i++) { | ||
| 267 | // SINE | ||
| 268 | sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2; | ||
| 269 | |||
| 270 | // SQUARE | ||
| 271 | // if (((int)places[i]) >= 1024){ | ||
| 272 | // sum += 0xFF >> 2; | ||
| 273 | // } else { | ||
| 274 | // sum += 0x00; | ||
| 275 | // } | ||
| 276 | |||
| 277 | places[i] += frequencies[i]; | ||
| 278 | |||
| 279 | if (places[i] >= SINE_LENGTH) | ||
| 280 | places[i] -= SINE_LENGTH; | ||
| 281 | } | ||
| 282 | OCR4A = sum; | ||
| 283 | } | ||
| 284 | #else | ||
| 285 | if (voices > 0) { | ||
| 286 | float freq; | ||
| 287 | if (polyphony_rate > 0) { | ||
| 288 | if (voices > 1) { | ||
| 289 | voice_place %= voices; | ||
| 290 | if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { | ||
| 291 | voice_place = (voice_place + 1) % voices; | ||
| 292 | place = 0.0; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | #ifdef VIBRATO_ENABLE | ||
| 296 | if (vibrato_strength > 0) { | ||
| 297 | freq = vibrato(frequencies[voice_place]); | ||
| 298 | } else { | ||
| 299 | #else | ||
| 300 | { | ||
| 301 | #endif | ||
| 302 | freq = frequencies[voice_place]; | ||
| 303 | } | ||
| 304 | } else { | ||
| 305 | if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { | ||
| 306 | frequency = frequency * pow(2, 440/frequency/12/2); | ||
| 307 | } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { | ||
| 308 | frequency = frequency * pow(2, -440/frequency/12/2); | ||
| 309 | } else { | ||
| 310 | frequency = frequencies[voices - 1]; | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | #ifdef VIBRATO_ENABLE | ||
| 315 | if (vibrato_strength > 0) { | ||
| 316 | freq = vibrato(frequency); | ||
| 317 | } else { | ||
| 318 | #else | ||
| 319 | { | ||
| 320 | #endif | ||
| 321 | freq = frequency; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | if (envelope_index < 65535) { | ||
| 326 | envelope_index++; | ||
| 327 | } | ||
| 328 | freq = voice_envelope(freq); | ||
| 329 | |||
| 330 | if (freq < 30.517578125) | ||
| 331 | freq = 30.52; | ||
| 332 | NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period | ||
| 333 | NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period | ||
| 334 | } | ||
| 335 | #endif | ||
| 336 | } | ||
| 337 | |||
| 338 | // SAMPLE | ||
| 339 | // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]); | ||
| 340 | |||
| 341 | // place_int++; | ||
| 342 | |||
| 343 | // if (place_int >= sample_length) | ||
| 344 | // if (repeat) | ||
| 345 | // place_int -= sample_length; | ||
| 346 | // else | ||
| 347 | // DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 348 | |||
| 349 | |||
| 350 | if (playing_notes) { | ||
| 351 | #ifdef PWM_AUDIO | ||
| 352 | OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0; | ||
| 353 | |||
| 354 | place += note_frequency; | ||
| 355 | if (place >= SINE_LENGTH) | ||
| 356 | place -= SINE_LENGTH; | ||
| 357 | #else | ||
| 358 | if (note_frequency > 0) { | ||
| 359 | float freq; | ||
| 360 | |||
| 361 | #ifdef VIBRATO_ENABLE | ||
| 362 | if (vibrato_strength > 0) { | ||
| 363 | freq = vibrato(note_frequency); | ||
| 364 | } else { | ||
| 365 | #else | ||
| 366 | { | ||
| 367 | #endif | ||
| 368 | freq = note_frequency; | ||
| 369 | } | ||
| 370 | |||
| 371 | if (envelope_index < 65535) { | ||
| 372 | envelope_index++; | ||
| 373 | } | ||
| 374 | freq = voice_envelope(freq); | ||
| 375 | |||
| 376 | NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period | ||
| 377 | NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period | ||
| 378 | } else { | ||
| 379 | NOTE_PERIOD = 0; | ||
| 380 | NOTE_DUTY_CYCLE = 0; | ||
| 381 | } | ||
| 382 | #endif | ||
| 383 | |||
| 384 | |||
| 385 | note_position++; | ||
| 386 | bool end_of_note = false; | ||
| 387 | if (NOTE_PERIOD > 0) | ||
| 388 | end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF)); | ||
| 389 | else | ||
| 390 | end_of_note = (note_position >= (note_length * 0x7FF)); | ||
| 391 | if (end_of_note) { | ||
| 392 | current_note++; | ||
| 393 | if (current_note >= notes_count) { | ||
| 394 | if (notes_repeat) { | ||
| 395 | current_note = 0; | ||
| 396 | } else { | ||
| 397 | #ifdef PWM_AUDIO | ||
| 398 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 399 | #else | ||
| 400 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 401 | DISABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 402 | #endif | ||
| 403 | playing_notes = false; | ||
| 404 | return; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | if (!note_resting && (notes_rest > 0)) { | ||
| 408 | note_resting = true; | ||
| 409 | note_frequency = 0; | ||
| 410 | note_length = notes_rest; | ||
| 411 | current_note--; | ||
| 412 | } else { | ||
| 413 | note_resting = false; | ||
| 414 | #ifdef PWM_AUDIO | ||
| 415 | note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||
| 416 | note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100); | ||
| 417 | #else | ||
| 418 | envelope_index = 0; | ||
| 419 | note_frequency = (*notes_pointer)[current_note][0]; | ||
| 420 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
| 421 | #endif | ||
| 422 | } | ||
| 423 | note_position = 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | } | ||
| 427 | |||
| 428 | if (!audio_config.enable) { | ||
| 429 | playing_notes = false; | ||
| 430 | playing_note = false; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | void play_note(float freq, int vol) { | ||
| 435 | |||
| 436 | if (!audio_initialized) { | ||
| 437 | audio_init(); | ||
| 438 | } | ||
| 439 | |||
| 440 | if (audio_config.enable && voices < 8) { | ||
| 441 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 442 | |||
| 443 | // Cancel notes if notes are playing | ||
| 444 | if (playing_notes) | ||
| 445 | stop_all_notes(); | ||
| 446 | |||
| 447 | playing_note = true; | ||
| 448 | |||
| 449 | envelope_index = 0; | ||
| 450 | |||
| 451 | #ifdef PWM_AUDIO | ||
| 452 | freq = freq / SAMPLE_RATE; | ||
| 453 | #endif | ||
| 454 | if (freq > 0) { | ||
| 455 | frequencies[voices] = freq; | ||
| 456 | volumes[voices] = vol; | ||
| 457 | voices++; | ||
| 458 | } | ||
| 459 | |||
| 460 | #ifdef PWM_AUDIO | ||
| 461 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 462 | #else | ||
| 463 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 464 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 465 | #endif | ||
| 466 | } | ||
| 467 | |||
| 468 | } | ||
| 469 | |||
| 470 | void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) | ||
| 471 | { | ||
| 472 | |||
| 473 | if (!audio_initialized) { | ||
| 474 | audio_init(); | ||
| 475 | } | ||
| 476 | |||
| 477 | if (audio_config.enable) { | ||
| 478 | |||
| 479 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 480 | |||
| 481 | // Cancel note if a note is playing | ||
| 482 | if (playing_note) | ||
| 483 | stop_all_notes(); | ||
| 484 | |||
| 485 | playing_notes = true; | ||
| 486 | |||
| 487 | notes_pointer = np; | ||
| 488 | notes_count = n_count; | ||
| 489 | notes_repeat = n_repeat; | ||
| 490 | notes_rest = n_rest; | ||
| 491 | |||
| 492 | place = 0; | ||
| 493 | current_note = 0; | ||
| 494 | |||
| 495 | #ifdef PWM_AUDIO | ||
| 496 | note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; | ||
| 497 | note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100); | ||
| 498 | #else | ||
| 499 | note_frequency = (*notes_pointer)[current_note][0]; | ||
| 500 | note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); | ||
| 501 | #endif | ||
| 502 | note_position = 0; | ||
| 503 | |||
| 504 | |||
| 505 | #ifdef PWM_AUDIO | ||
| 506 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 507 | #else | ||
| 508 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 509 | ENABLE_AUDIO_COUNTER_3_OUTPUT; | ||
| 510 | #endif | ||
| 511 | } | ||
| 512 | |||
| 513 | } | ||
| 514 | |||
| 515 | #ifdef PWM_AUDIO | ||
| 516 | void play_sample(uint8_t * s, uint16_t l, bool r) { | ||
| 517 | if (!audio_initialized) { | ||
| 518 | audio_init(); | ||
| 519 | } | ||
| 520 | |||
| 521 | if (audio_config.enable) { | ||
| 522 | DISABLE_AUDIO_COUNTER_3_ISR; | ||
| 523 | stop_all_notes(); | ||
| 524 | place_int = 0; | ||
| 525 | sample = s; | ||
| 526 | sample_length = l; | ||
| 527 | repeat = r; | ||
| 528 | |||
| 529 | ENABLE_AUDIO_COUNTER_3_ISR; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | #endif | ||
| 533 | |||
| 534 | |||
| 535 | void audio_toggle(void) { | ||
| 536 | audio_config.enable ^= 1; | ||
| 537 | eeconfig_update_audio(audio_config.raw); | ||
| 538 | } | ||
| 539 | |||
| 540 | void audio_on(void) { | ||
| 541 | audio_config.enable = 1; | ||
| 542 | eeconfig_update_audio(audio_config.raw); | ||
| 543 | } | ||
| 544 | |||
| 545 | void audio_off(void) { | ||
| 546 | audio_config.enable = 0; | ||
| 547 | eeconfig_update_audio(audio_config.raw); | ||
| 548 | } | ||
| 549 | |||
| 550 | #ifdef VIBRATO_ENABLE | ||
| 551 | |||
| 552 | // Vibrato rate functions | ||
| 553 | |||
| 554 | void set_vibrato_rate(float rate) { | ||
| 555 | vibrato_rate = rate; | ||
| 556 | } | ||
| 557 | |||
| 558 | void increase_vibrato_rate(float change) { | ||
| 559 | vibrato_rate *= change; | ||
| 560 | } | ||
| 561 | |||
| 562 | void decrease_vibrato_rate(float change) { | ||
| 563 | vibrato_rate /= change; | ||
| 564 | } | ||
| 565 | |||
| 566 | #ifdef VIBRATO_STRENGTH_ENABLE | ||
| 567 | |||
| 568 | void set_vibrato_strength(float strength) { | ||
| 569 | vibrato_strength = strength; | ||
| 570 | } | ||
| 571 | |||
| 572 | void increase_vibrato_strength(float change) { | ||
| 573 | vibrato_strength *= change; | ||
| 574 | } | ||
| 575 | |||
| 576 | void decrease_vibrato_strength(float change) { | ||
| 577 | vibrato_strength /= change; | ||
| 578 | } | ||
| 579 | |||
| 580 | #endif /* VIBRATO_STRENGTH_ENABLE */ | ||
| 581 | |||
| 582 | #endif /* VIBRATO_ENABLE */ | ||
| 583 | |||
| 584 | // Polyphony functions | ||
| 585 | |||
| 586 | void set_polyphony_rate(float rate) { | ||
| 587 | polyphony_rate = rate; | ||
| 588 | } | ||
| 589 | |||
| 590 | void enable_polyphony() { | ||
| 591 | polyphony_rate = 5; | ||
| 592 | } | ||
| 593 | |||
| 594 | void disable_polyphony() { | ||
| 595 | polyphony_rate = 0; | ||
| 596 | } | ||
| 597 | |||
| 598 | void increase_polyphony_rate(float change) { | ||
| 599 | polyphony_rate *= change; | ||
| 600 | } | ||
| 601 | |||
| 602 | void decrease_polyphony_rate(float change) { | ||
| 603 | polyphony_rate /= change; | ||
| 604 | } | ||
| 605 | |||
| 606 | // Timbre function | ||
| 607 | |||
| 608 | void set_timbre(float timbre) { | ||
| 609 | note_timbre = timbre; | ||
| 610 | } | ||
| 611 | |||
| 612 | // Tempo functions | ||
| 613 | |||
| 614 | void set_tempo(uint8_t tempo) { | ||
| 615 | note_tempo = tempo; | ||
| 616 | } | ||
| 617 | |||
| 618 | void decrease_tempo(uint8_t tempo_change) { | ||
| 619 | note_tempo += tempo_change; | ||
| 620 | } | ||
| 621 | |||
| 622 | void increase_tempo(uint8_t tempo_change) { | ||
| 623 | if (note_tempo - tempo_change < 10) { | ||
| 624 | note_tempo = 10; | ||
| 625 | } else { | ||
| 626 | note_tempo -= tempo_change; | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | |||
| 631 | //------------------------------------------------------------------------------ | ||
| 632 | // Override these functions in your keymap file to play different tunes on | ||
| 633 | // startup and bootloader jump | ||
| 634 | __attribute__ ((weak)) | ||
| 635 | void play_startup_tone() | ||
| 636 | { | ||
| 637 | } | ||
| 638 | |||
| 639 | __attribute__ ((weak)) | ||
| 640 | void play_goodbye_tone() | ||
| 641 | { | ||
| 642 | } | ||
| 643 | //------------------------------------------------------------------------------ | ||
diff --git a/quantum/audio/luts.c b/quantum/audio/luts.c new file mode 100644 index 000000000..9f3de9a05 --- /dev/null +++ b/quantum/audio/luts.c | |||
| @@ -0,0 +1,382 @@ | |||
| 1 | #include <avr/io.h> | ||
| 2 | #include <avr/interrupt.h> | ||
| 3 | #include <avr/pgmspace.h> | ||
| 4 | #include "luts.h" | ||
| 5 | |||
| 6 | const float vibrato_lut[VIBRATO_LUT_LENGTH] = | ||
| 7 | { | ||
| 8 | 1.0022336811487, | ||
| 9 | 1.0042529943610, | ||
| 10 | 1.0058584256028, | ||
| 11 | 1.0068905285205, | ||
| 12 | 1.0072464122237, | ||
| 13 | 1.0068905285205, | ||
| 14 | 1.0058584256028, | ||
| 15 | 1.0042529943610, | ||
| 16 | 1.0022336811487, | ||
| 17 | 1.0000000000000, | ||
| 18 | 0.9977712970630, | ||
| 19 | 0.9957650169978, | ||
| 20 | 0.9941756956510, | ||
| 21 | 0.9931566259436, | ||
| 22 | 0.9928057204913, | ||
| 23 | 0.9931566259436, | ||
| 24 | 0.9941756956510, | ||
| 25 | 0.9957650169978, | ||
| 26 | 0.9977712970630, | ||
| 27 | 1.0000000000000, | ||
| 28 | }; | ||
| 29 | |||
| 30 | const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH] = | ||
| 31 | { | ||
| 32 | 0x8E0B, | ||
| 33 | 0x8C02, | ||
| 34 | 0x8A00, | ||
| 35 | 0x8805, | ||
| 36 | 0x8612, | ||
| 37 | 0x8426, | ||
| 38 | 0x8241, | ||
| 39 | 0x8063, | ||
| 40 | 0x7E8C, | ||
| 41 | 0x7CBB, | ||
| 42 | 0x7AF2, | ||
| 43 | 0x792E, | ||
| 44 | 0x7772, | ||
| 45 | 0x75BB, | ||
| 46 | 0x740B, | ||
| 47 | 0x7261, | ||
| 48 | 0x70BD, | ||
| 49 | 0x6F20, | ||
| 50 | 0x6D88, | ||
| 51 | 0x6BF6, | ||
| 52 | 0x6A69, | ||
| 53 | 0x68E3, | ||
| 54 | 0x6762, | ||
| 55 | 0x65E6, | ||
| 56 | 0x6470, | ||
| 57 | 0x6300, | ||
| 58 | 0x6194, | ||
| 59 | 0x602E, | ||
| 60 | 0x5ECD, | ||
| 61 | 0x5D71, | ||
| 62 | 0x5C1A, | ||
| 63 | 0x5AC8, | ||
| 64 | 0x597B, | ||
| 65 | 0x5833, | ||
| 66 | 0x56EF, | ||
| 67 | 0x55B0, | ||
| 68 | 0x5475, | ||
| 69 | 0x533F, | ||
| 70 | 0x520E, | ||
| 71 | 0x50E1, | ||
| 72 | 0x4FB8, | ||
| 73 | 0x4E93, | ||
| 74 | 0x4D73, | ||
| 75 | 0x4C57, | ||
| 76 | 0x4B3E, | ||
| 77 | 0x4A2A, | ||
| 78 | 0x491A, | ||
| 79 | 0x480E, | ||
| 80 | 0x4705, | ||
| 81 | 0x4601, | ||
| 82 | 0x4500, | ||
| 83 | 0x4402, | ||
| 84 | 0x4309, | ||
| 85 | 0x4213, | ||
| 86 | 0x4120, | ||
| 87 | 0x4031, | ||
| 88 | 0x3F46, | ||
| 89 | 0x3E5D, | ||
| 90 | 0x3D79, | ||
| 91 | 0x3C97, | ||
| 92 | 0x3BB9, | ||
| 93 | 0x3ADD, | ||
| 94 | 0x3A05, | ||
| 95 | 0x3930, | ||
| 96 | 0x385E, | ||
| 97 | 0x3790, | ||
| 98 | 0x36C4, | ||
| 99 | 0x35FB, | ||
| 100 | 0x3534, | ||
| 101 | 0x3471, | ||
| 102 | 0x33B1, | ||
| 103 | 0x32F3, | ||
| 104 | 0x3238, | ||
| 105 | 0x3180, | ||
| 106 | 0x30CA, | ||
| 107 | 0x3017, | ||
| 108 | 0x2F66, | ||
| 109 | 0x2EB8, | ||
| 110 | 0x2E0D, | ||
| 111 | 0x2D64, | ||
| 112 | 0x2CBD, | ||
| 113 | 0x2C19, | ||
| 114 | 0x2B77, | ||
| 115 | 0x2AD8, | ||
| 116 | 0x2A3A, | ||
| 117 | 0x299F, | ||
| 118 | 0x2907, | ||
| 119 | 0x2870, | ||
| 120 | 0x27DC, | ||
| 121 | 0x2749, | ||
| 122 | 0x26B9, | ||
| 123 | 0x262B, | ||
| 124 | 0x259F, | ||
| 125 | 0x2515, | ||
| 126 | 0x248D, | ||
| 127 | 0x2407, | ||
| 128 | 0x2382, | ||
| 129 | 0x2300, | ||
| 130 | 0x2280, | ||
| 131 | 0x2201, | ||
| 132 | 0x2184, | ||
| 133 | 0x2109, | ||
| 134 | 0x2090, | ||
| 135 | 0x2018, | ||
| 136 | 0x1FA3, | ||
| 137 | 0x1F2E, | ||
| 138 | 0x1EBC, | ||
| 139 | 0x1E4B, | ||
| 140 | 0x1DDC, | ||
| 141 | 0x1D6E, | ||
| 142 | 0x1D02, | ||
| 143 | 0x1C98, | ||
| 144 | 0x1C2F, | ||
| 145 | 0x1BC8, | ||
| 146 | 0x1B62, | ||
| 147 | 0x1AFD, | ||
| 148 | 0x1A9A, | ||
| 149 | 0x1A38, | ||
| 150 | 0x19D8, | ||
| 151 | 0x1979, | ||
| 152 | 0x191C, | ||
| 153 | 0x18C0, | ||
| 154 | 0x1865, | ||
| 155 | 0x180B, | ||
| 156 | 0x17B3, | ||
| 157 | 0x175C, | ||
| 158 | 0x1706, | ||
| 159 | 0x16B2, | ||
| 160 | 0x165E, | ||
| 161 | 0x160C, | ||
| 162 | 0x15BB, | ||
| 163 | 0x156C, | ||
| 164 | 0x151D, | ||
| 165 | 0x14CF, | ||
| 166 | 0x1483, | ||
| 167 | 0x1438, | ||
| 168 | 0x13EE, | ||
| 169 | 0x13A4, | ||
| 170 | 0x135C, | ||
| 171 | 0x1315, | ||
| 172 | 0x12CF, | ||
| 173 | 0x128A, | ||
| 174 | 0x1246, | ||
| 175 | 0x1203, | ||
| 176 | 0x11C1, | ||
| 177 | 0x1180, | ||
| 178 | 0x1140, | ||
| 179 | 0x1100, | ||
| 180 | 0x10C2, | ||
| 181 | 0x1084, | ||
| 182 | 0x1048, | ||
| 183 | 0x100C, | ||
| 184 | 0xFD1, | ||
| 185 | 0xF97, | ||
| 186 | 0xF5E, | ||
| 187 | 0xF25, | ||
| 188 | 0xEEE, | ||
| 189 | 0xEB7, | ||
| 190 | 0xE81, | ||
| 191 | 0xE4C, | ||
| 192 | 0xE17, | ||
| 193 | 0xDE4, | ||
| 194 | 0xDB1, | ||
| 195 | 0xD7E, | ||
| 196 | 0xD4D, | ||
| 197 | 0xD1C, | ||
| 198 | 0xCEC, | ||
| 199 | 0xCBC, | ||
| 200 | 0xC8E, | ||
| 201 | 0xC60, | ||
| 202 | 0xC32, | ||
| 203 | 0xC05, | ||
| 204 | 0xBD9, | ||
| 205 | 0xBAE, | ||
| 206 | 0xB83, | ||
| 207 | 0xB59, | ||
| 208 | 0xB2F, | ||
| 209 | 0xB06, | ||
| 210 | 0xADD, | ||
| 211 | 0xAB6, | ||
| 212 | 0xA8E, | ||
| 213 | 0xA67, | ||
| 214 | 0xA41, | ||
| 215 | 0xA1C, | ||
| 216 | 0x9F7, | ||
| 217 | 0x9D2, | ||
| 218 | 0x9AE, | ||
| 219 | 0x98A, | ||
| 220 | 0x967, | ||
| 221 | 0x945, | ||
| 222 | 0x923, | ||
| 223 | 0x901, | ||
| 224 | 0x8E0, | ||
| 225 | 0x8C0, | ||
| 226 | 0x8A0, | ||
| 227 | 0x880, | ||
| 228 | 0x861, | ||
| 229 | 0x842, | ||
| 230 | 0x824, | ||
| 231 | 0x806, | ||
| 232 | 0x7E8, | ||
| 233 | 0x7CB, | ||
| 234 | 0x7AF, | ||
| 235 | 0x792, | ||
| 236 | 0x777, | ||
| 237 | 0x75B, | ||
| 238 | 0x740, | ||
| 239 | 0x726, | ||
| 240 | 0x70B, | ||
| 241 | 0x6F2, | ||
| 242 | 0x6D8, | ||
| 243 | 0x6BF, | ||
| 244 | 0x6A6, | ||
| 245 | 0x68E, | ||
| 246 | 0x676, | ||
| 247 | 0x65E, | ||
| 248 | 0x647, | ||
| 249 | 0x630, | ||
| 250 | 0x619, | ||
| 251 | 0x602, | ||
| 252 | 0x5EC, | ||
| 253 | 0x5D7, | ||
| 254 | 0x5C1, | ||
| 255 | 0x5AC, | ||
| 256 | 0x597, | ||
| 257 | 0x583, | ||
| 258 | 0x56E, | ||
| 259 | 0x55B, | ||
| 260 | 0x547, | ||
| 261 | 0x533, | ||
| 262 | 0x520, | ||
| 263 | 0x50E, | ||
| 264 | 0x4FB, | ||
| 265 | 0x4E9, | ||
| 266 | 0x4D7, | ||
| 267 | 0x4C5, | ||
| 268 | 0x4B3, | ||
| 269 | 0x4A2, | ||
| 270 | 0x491, | ||
| 271 | 0x480, | ||
| 272 | 0x470, | ||
| 273 | 0x460, | ||
| 274 | 0x450, | ||
| 275 | 0x440, | ||
| 276 | 0x430, | ||
| 277 | 0x421, | ||
| 278 | 0x412, | ||
| 279 | 0x403, | ||
| 280 | 0x3F4, | ||
| 281 | 0x3E5, | ||
| 282 | 0x3D7, | ||
| 283 | 0x3C9, | ||
| 284 | 0x3BB, | ||
| 285 | 0x3AD, | ||
| 286 | 0x3A0, | ||
| 287 | 0x393, | ||
| 288 | 0x385, | ||
| 289 | 0x379, | ||
| 290 | 0x36C, | ||
| 291 | 0x35F, | ||
| 292 | 0x353, | ||
| 293 | 0x347, | ||
| 294 | 0x33B, | ||
| 295 | 0x32F, | ||
| 296 | 0x323, | ||
| 297 | 0x318, | ||
| 298 | 0x30C, | ||
| 299 | 0x301, | ||
| 300 | 0x2F6, | ||
| 301 | 0x2EB, | ||
| 302 | 0x2E0, | ||
| 303 | 0x2D6, | ||
| 304 | 0x2CB, | ||
| 305 | 0x2C1, | ||
| 306 | 0x2B7, | ||
| 307 | 0x2AD, | ||
| 308 | 0x2A3, | ||
| 309 | 0x299, | ||
| 310 | 0x290, | ||
| 311 | 0x287, | ||
| 312 | 0x27D, | ||
| 313 | 0x274, | ||
| 314 | 0x26B, | ||
| 315 | 0x262, | ||
| 316 | 0x259, | ||
| 317 | 0x251, | ||
| 318 | 0x248, | ||
| 319 | 0x240, | ||
| 320 | 0x238, | ||
| 321 | 0x230, | ||
| 322 | 0x228, | ||
| 323 | 0x220, | ||
| 324 | 0x218, | ||
| 325 | 0x210, | ||
| 326 | 0x209, | ||
| 327 | 0x201, | ||
| 328 | 0x1FA, | ||
| 329 | 0x1F2, | ||
| 330 | 0x1EB, | ||
| 331 | 0x1E4, | ||
| 332 | 0x1DD, | ||
| 333 | 0x1D6, | ||
| 334 | 0x1D0, | ||
| 335 | 0x1C9, | ||
| 336 | 0x1C2, | ||
| 337 | 0x1BC, | ||
| 338 | 0x1B6, | ||
| 339 | 0x1AF, | ||
| 340 | 0x1A9, | ||
| 341 | 0x1A3, | ||
| 342 | 0x19D, | ||
| 343 | 0x197, | ||
| 344 | 0x191, | ||
| 345 | 0x18C, | ||
| 346 | 0x186, | ||
| 347 | 0x180, | ||
| 348 | 0x17B, | ||
| 349 | 0x175, | ||
| 350 | 0x170, | ||
| 351 | 0x16B, | ||
| 352 | 0x165, | ||
| 353 | 0x160, | ||
| 354 | 0x15B, | ||
| 355 | 0x156, | ||
| 356 | 0x151, | ||
| 357 | 0x14C, | ||
| 358 | 0x148, | ||
| 359 | 0x143, | ||
| 360 | 0x13E, | ||
| 361 | 0x13A, | ||
| 362 | 0x135, | ||
| 363 | 0x131, | ||
| 364 | 0x12C, | ||
| 365 | 0x128, | ||
| 366 | 0x124, | ||
| 367 | 0x120, | ||
| 368 | 0x11C, | ||
| 369 | 0x118, | ||
| 370 | 0x114, | ||
| 371 | 0x110, | ||
| 372 | 0x10C, | ||
| 373 | 0x108, | ||
| 374 | 0x104, | ||
| 375 | 0x100, | ||
| 376 | 0xFD, | ||
| 377 | 0xF9, | ||
| 378 | 0xF5, | ||
| 379 | 0xF2, | ||
| 380 | 0xEE, | ||
| 381 | }; | ||
| 382 | |||
diff --git a/quantum/audio/luts.h b/quantum/audio/luts.h new file mode 100644 index 000000000..7df3078a7 --- /dev/null +++ b/quantum/audio/luts.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #include <avr/io.h> | ||
| 2 | #include <avr/interrupt.h> | ||
| 3 | #include <avr/pgmspace.h> | ||
| 4 | |||
| 5 | #ifndef LUTS_H | ||
| 6 | #define LUTS_H | ||
| 7 | |||
| 8 | #define VIBRATO_LUT_LENGTH 20 | ||
| 9 | |||
| 10 | #define FREQUENCY_LUT_LENGTH 349 | ||
| 11 | |||
| 12 | extern const float vibrato_lut[VIBRATO_LUT_LENGTH]; | ||
| 13 | extern const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH]; | ||
| 14 | |||
| 15 | #endif /* LUTS_H */ \ No newline at end of file | ||
diff --git a/quantum/audio/musical_notes.h b/quantum/audio/musical_notes.h new file mode 100644 index 000000000..b08d16a6f --- /dev/null +++ b/quantum/audio/musical_notes.h | |||
| @@ -0,0 +1,217 @@ | |||
| 1 | #ifndef MUSICAL_NOTES_H | ||
| 2 | #define MUSICAL_NOTES_H | ||
| 3 | |||
| 4 | // Tempo Placeholder | ||
| 5 | #define TEMPO_DEFAULT 100 | ||
| 6 | |||
| 7 | |||
| 8 | #define SONG(notes...) { notes } | ||
| 9 | |||
| 10 | |||
| 11 | // Note Types | ||
| 12 | #define MUSICAL_NOTE(note, duration) {(NOTE##note), duration} | ||
| 13 | #define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64) | ||
| 14 | #define HALF_NOTE(note) MUSICAL_NOTE(note, 32) | ||
| 15 | #define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16) | ||
| 16 | #define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8) | ||
| 17 | #define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4) | ||
| 18 | |||
| 19 | #define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64+32) | ||
| 20 | #define HALF_DOT_NOTE(note) MUSICAL_NOTE(note, 32+16) | ||
| 21 | #define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16+8) | ||
| 22 | #define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8+4) | ||
| 23 | #define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4+2) | ||
| 24 | |||
| 25 | // Note Type Shortcuts | ||
| 26 | #define M__NOTE(note, duration) MUSICAL_NOTE(note, duration) | ||
| 27 | #define W__NOTE(n) WHOLE_NOTE(n) | ||
| 28 | #define H__NOTE(n) HALF_NOTE(n) | ||
| 29 | #define Q__NOTE(n) QUARTER_NOTE(n) | ||
| 30 | #define E__NOTE(n) EIGHTH_NOTE(n) | ||
| 31 | #define S__NOTE(n) SIXTEENTH_NOTE(n) | ||
| 32 | #define WD_NOTE(n) WHOLE_DOT_NOTE(n) | ||
| 33 | #define HD_NOTE(n) HALF_DOT_NOTE(n) | ||
| 34 | #define QD_NOTE(n) QUARTER_DOT_NOTE(n) | ||
| 35 | #define ED_NOTE(n) EIGHTH_DOT_NOTE(n) | ||
| 36 | #define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n) | ||
| 37 | |||
| 38 | // Note Styles | ||
| 39 | // Staccato makes sure there is a rest between each note. Think: TA TA TA | ||
| 40 | // Legato makes notes flow together. Think: TAAA | ||
| 41 | #define STACCATO 0.01 | ||
| 42 | #define LEGATO 0 | ||
| 43 | |||
| 44 | // Note Timbre | ||
| 45 | // Changes how the notes sound | ||
| 46 | #define TIMBRE_12 0.125 | ||
| 47 | #define TIMBRE_25 0.250 | ||
| 48 | #define TIMBRE_50 0.500 | ||
| 49 | #define TIMBRE_75 0.750 | ||
| 50 | #define TIMBRE_DEFAULT TIMBRE_50 | ||
| 51 | |||
| 52 | |||
| 53 | // Notes - # = Octave | ||
| 54 | |||
| 55 | #define NOTE_REST 0.00 | ||
| 56 | |||
| 57 | /* These notes are currently bugged | ||
| 58 | #define NOTE_C0 16.35 | ||
| 59 | #define NOTE_CS0 17.32 | ||
| 60 | #define NOTE_D0 18.35 | ||
| 61 | #define NOTE_DS0 19.45 | ||
| 62 | #define NOTE_E0 20.60 | ||
| 63 | #define NOTE_F0 21.83 | ||
| 64 | #define NOTE_FS0 23.12 | ||
| 65 | #define NOTE_G0 24.50 | ||
| 66 | #define NOTE_GS0 25.96 | ||
| 67 | #define NOTE_A0 27.50 | ||
| 68 | #define NOTE_AS0 29.14 | ||
| 69 | #define NOTE_B0 30.87 | ||
| 70 | #define NOTE_C1 32.70 | ||
| 71 | #define NOTE_CS1 34.65 | ||
| 72 | #define NOTE_D1 36.71 | ||
| 73 | #define NOTE_DS1 38.89 | ||
| 74 | #define NOTE_E1 41.20 | ||
| 75 | #define NOTE_F1 43.65 | ||
| 76 | #define NOTE_FS1 46.25 | ||
| 77 | #define NOTE_G1 49.00 | ||
| 78 | #define NOTE_GS1 51.91 | ||
| 79 | #define NOTE_A1 55.00 | ||
| 80 | #define NOTE_AS1 58.27 | ||
| 81 | */ | ||
| 82 | |||
| 83 | #define NOTE_B1 61.74 | ||
| 84 | #define NOTE_C2 65.41 | ||
| 85 | #define NOTE_CS2 69.30 | ||
| 86 | #define NOTE_D2 73.42 | ||
| 87 | #define NOTE_DS2 77.78 | ||
| 88 | #define NOTE_E2 82.41 | ||
| 89 | #define NOTE_F2 87.31 | ||
| 90 | #define NOTE_FS2 92.50 | ||
| 91 | #define NOTE_G2 98.00 | ||
| 92 | #define NOTE_GS2 103.83 | ||
| 93 | #define NOTE_A2 110.00 | ||
| 94 | #define NOTE_AS2 116.54 | ||
| 95 | #define NOTE_B2 123.47 | ||
| 96 | #define NOTE_C3 130.81 | ||
| 97 | #define NOTE_CS3 138.59 | ||
| 98 | #define NOTE_D3 146.83 | ||
| 99 | #define NOTE_DS3 155.56 | ||
| 100 | #define NOTE_E3 164.81 | ||
| 101 | #define NOTE_F3 174.61 | ||
| 102 | #define NOTE_FS3 185.00 | ||
| 103 | #define NOTE_G3 196.00 | ||
| 104 | #define NOTE_GS3 207.65 | ||
| 105 | #define NOTE_A3 220.00 | ||
| 106 | #define NOTE_AS3 233.08 | ||
| 107 | #define NOTE_B3 246.94 | ||
| 108 | #define NOTE_C4 261.63 | ||
| 109 | #define NOTE_CS4 277.18 | ||
| 110 | #define NOTE_D4 293.66 | ||
| 111 | #define NOTE_DS4 311.13 | ||
| 112 | #define NOTE_E4 329.63 | ||
| 113 | #define NOTE_F4 349.23 | ||
| 114 | #define NOTE_FS4 369.99 | ||
| 115 | #define NOTE_G4 392.00 | ||
| 116 | #define NOTE_GS4 415.30 | ||
| 117 | #define NOTE_A4 440.00 | ||
| 118 | #define NOTE_AS4 466.16 | ||
| 119 | #define NOTE_B4 493.88 | ||
| 120 | #define NOTE_C5 523.25 | ||
| 121 | #define NOTE_CS5 554.37 | ||
| 122 | #define NOTE_D5 587.33 | ||
| 123 | #define NOTE_DS5 622.25 | ||
| 124 | #define NOTE_E5 659.26 | ||
| 125 | #define NOTE_F5 698.46 | ||
| 126 | #define NOTE_FS5 739.99 | ||
| 127 | #define NOTE_G5 783.99 | ||
| 128 | #define NOTE_GS5 830.61 | ||
| 129 | #define NOTE_A5 880.00 | ||
| 130 | #define NOTE_AS5 932.33 | ||
| 131 | #define NOTE_B5 987.77 | ||
| 132 | #define NOTE_C6 1046.50 | ||
| 133 | #define NOTE_CS6 1108.73 | ||
| 134 | #define NOTE_D6 1174.66 | ||
| 135 | #define NOTE_DS6 1244.51 | ||
| 136 | #define NOTE_E6 1318.51 | ||
| 137 | #define NOTE_F6 1396.91 | ||
| 138 | #define NOTE_FS6 1479.98 | ||
| 139 | #define NOTE_G6 1567.98 | ||
| 140 | #define NOTE_GS6 1661.22 | ||
| 141 | #define NOTE_A6 1760.00 | ||
| 142 | #define NOTE_AS6 1864.66 | ||
| 143 | #define NOTE_B6 1975.53 | ||
| 144 | #define NOTE_C7 2093.00 | ||
| 145 | #define NOTE_CS7 2217.46 | ||
| 146 | #define NOTE_D7 2349.32 | ||
| 147 | #define NOTE_DS7 2489.02 | ||
| 148 | #define NOTE_E7 2637.02 | ||
| 149 | #define NOTE_F7 2793.83 | ||
| 150 | #define NOTE_FS7 2959.96 | ||
| 151 | #define NOTE_G7 3135.96 | ||
| 152 | #define NOTE_GS7 3322.44 | ||
| 153 | #define NOTE_A7 3520.00 | ||
| 154 | #define NOTE_AS7 3729.31 | ||
| 155 | #define NOTE_B7 3951.07 | ||
| 156 | #define NOTE_C8 4186.01 | ||
| 157 | #define NOTE_CS8 4434.92 | ||
| 158 | #define NOTE_D8 4698.64 | ||
| 159 | #define NOTE_DS8 4978.03 | ||
| 160 | #define NOTE_E8 5274.04 | ||
| 161 | #define NOTE_F8 5587.65 | ||
| 162 | #define NOTE_FS8 5919.91 | ||
| 163 | #define NOTE_G8 6271.93 | ||
| 164 | #define NOTE_GS8 6644.88 | ||
| 165 | #define NOTE_A8 7040.00 | ||
| 166 | #define NOTE_AS8 7458.62 | ||
| 167 | #define NOTE_B8 7902.13 | ||
| 168 | |||
| 169 | // Flat Aliases | ||
| 170 | #define NOTE_DF0 NOTE_CS0 | ||
| 171 | #define NOTE_EF0 NOTE_DS0 | ||
| 172 | #define NOTE_GF0 NOTE_FS0 | ||
| 173 | #define NOTE_AF0 NOTE_GS0 | ||
| 174 | #define NOTE_BF0 NOTE_AS0 | ||
| 175 | #define NOTE_DF1 NOTE_CS1 | ||
| 176 | #define NOTE_EF1 NOTE_DS1 | ||
| 177 | #define NOTE_GF1 NOTE_FS1 | ||
| 178 | #define NOTE_AF1 NOTE_GS1 | ||
| 179 | #define NOTE_BF1 NOTE_AS1 | ||
| 180 | #define NOTE_DF2 NOTE_CS2 | ||
| 181 | #define NOTE_EF2 NOTE_DS2 | ||
| 182 | #define NOTE_GF2 NOTE_FS2 | ||
| 183 | #define NOTE_AF2 NOTE_GS2 | ||
| 184 | #define NOTE_BF2 NOTE_AS2 | ||
| 185 | #define NOTE_DF3 NOTE_CS3 | ||
| 186 | #define NOTE_EF3 NOTE_DS3 | ||
| 187 | #define NOTE_GF3 NOTE_FS3 | ||
| 188 | #define NOTE_AF3 NOTE_GS3 | ||
| 189 | #define NOTE_BF3 NOTE_AS3 | ||
| 190 | #define NOTE_DF4 NOTE_CS4 | ||
| 191 | #define NOTE_EF4 NOTE_DS4 | ||
| 192 | #define NOTE_GF4 NOTE_FS4 | ||
| 193 | #define NOTE_AF4 NOTE_GS4 | ||
| 194 | #define NOTE_BF4 NOTE_AS4 | ||
| 195 | #define NOTE_DF5 NOTE_CS5 | ||
| 196 | #define NOTE_EF5 NOTE_DS5 | ||
| 197 | #define NOTE_GF5 NOTE_FS5 | ||
| 198 | #define NOTE_AF5 NOTE_GS5 | ||
| 199 | #define NOTE_BF5 NOTE_AS5 | ||
| 200 | #define NOTE_DF6 NOTE_CS6 | ||
| 201 | #define NOTE_EF6 NOTE_DS6 | ||
| 202 | #define NOTE_GF6 NOTE_FS6 | ||
| 203 | #define NOTE_AF6 NOTE_GS6 | ||
| 204 | #define NOTE_BF6 NOTE_AS6 | ||
| 205 | #define NOTE_DF7 NOTE_CS7 | ||
| 206 | #define NOTE_EF7 NOTE_DS7 | ||
| 207 | #define NOTE_GF7 NOTE_FS7 | ||
| 208 | #define NOTE_AF7 NOTE_GS7 | ||
| 209 | #define NOTE_BF7 NOTE_AS7 | ||
| 210 | #define NOTE_DF8 NOTE_CS8 | ||
| 211 | #define NOTE_EF8 NOTE_DS8 | ||
| 212 | #define NOTE_GF8 NOTE_FS8 | ||
| 213 | #define NOTE_AF8 NOTE_GS8 | ||
| 214 | #define NOTE_BF8 NOTE_AS8 | ||
| 215 | |||
| 216 | |||
| 217 | #endif \ No newline at end of file | ||
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h new file mode 100644 index 000000000..fc6fcdeef --- /dev/null +++ b/quantum/audio/song_list.h | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | #include "musical_notes.h" | ||
| 2 | |||
| 3 | #ifndef SONG_LIST_H | ||
| 4 | #define SONG_LIST_H | ||
| 5 | |||
| 6 | #define ODE_TO_JOY \ | ||
| 7 | Q__NOTE(_E4), Q__NOTE(_E4), Q__NOTE(_F4), Q__NOTE(_G4), \ | ||
| 8 | Q__NOTE(_G4), Q__NOTE(_F4), Q__NOTE(_E4), Q__NOTE(_D4), \ | ||
| 9 | Q__NOTE(_C4), Q__NOTE(_C4), Q__NOTE(_D4), Q__NOTE(_E4), \ | ||
| 10 | QD_NOTE(_E4), E__NOTE(_D4), H__NOTE(_D4), | ||
| 11 | |||
| 12 | #define ROCK_A_BYE_BABY \ | ||
| 13 | QD_NOTE(_B4), E__NOTE(_D4), Q__NOTE(_B5), \ | ||
| 14 | H__NOTE(_A5), Q__NOTE(_G5), \ | ||
| 15 | QD_NOTE(_B4), E__NOTE(_D5), Q__NOTE(_G5), \ | ||
| 16 | H__NOTE(_FS5), | ||
| 17 | |||
| 18 | #define CLOSE_ENCOUNTERS_5_NOTE \ | ||
| 19 | Q__NOTE(_D5), \ | ||
| 20 | Q__NOTE(_E5), \ | ||
| 21 | Q__NOTE(_C5), \ | ||
| 22 | Q__NOTE(_C4), \ | ||
| 23 | Q__NOTE(_G4), | ||
| 24 | |||
| 25 | #define DOE_A_DEER \ | ||
| 26 | QD_NOTE(_C4), E__NOTE(_D4), \ | ||
| 27 | QD_NOTE(_E4), E__NOTE(_C4), \ | ||
| 28 | Q__NOTE(_E4), Q__NOTE(_C4), \ | ||
| 29 | Q__NOTE(_E4), | ||
| 30 | |||
| 31 | #define GOODBYE_SOUND \ | ||
| 32 | E__NOTE(_E7), \ | ||
| 33 | E__NOTE(_A6), \ | ||
| 34 | ED_NOTE(_E6), | ||
| 35 | |||
| 36 | #define STARTUP_SOUND \ | ||
| 37 | ED_NOTE(_E7 ), \ | ||
| 38 | E__NOTE(_CS7), \ | ||
| 39 | E__NOTE(_E6 ), \ | ||
| 40 | E__NOTE(_A6 ), \ | ||
| 41 | M__NOTE(_CS7, 20), | ||
| 42 | |||
| 43 | #define QWERTY_SOUND \ | ||
| 44 | E__NOTE(_GS6 ), \ | ||
| 45 | E__NOTE(_A6 ), \ | ||
| 46 | S__NOTE(_REST), \ | ||
| 47 | Q__NOTE(_E7 ), | ||
| 48 | |||
| 49 | #define COLEMAK_SOUND \ | ||
| 50 | E__NOTE(_GS6 ), \ | ||
| 51 | E__NOTE(_A6 ), \ | ||
| 52 | S__NOTE(_REST), \ | ||
| 53 | ED_NOTE(_E7 ), \ | ||
| 54 | S__NOTE(_REST), \ | ||
| 55 | ED_NOTE(_GS7 ), | ||
| 56 | |||
| 57 | #define DVORAK_SOUND \ | ||
| 58 | E__NOTE(_GS6 ), \ | ||
| 59 | E__NOTE(_A6 ), \ | ||
| 60 | S__NOTE(_REST), \ | ||
| 61 | E__NOTE(_E7 ), \ | ||
| 62 | S__NOTE(_REST), \ | ||
| 63 | E__NOTE(_FS7 ), \ | ||
| 64 | S__NOTE(_REST), \ | ||
| 65 | E__NOTE(_E7 ), | ||
| 66 | |||
| 67 | #define PLOVER_SOUND \ | ||
| 68 | E__NOTE(_GS6 ), \ | ||
| 69 | E__NOTE(_A6 ), \ | ||
| 70 | S__NOTE(_REST), \ | ||
| 71 | ED_NOTE(_E7 ), \ | ||
| 72 | S__NOTE(_REST), \ | ||
| 73 | ED_NOTE(_A7 ), | ||
| 74 | |||
| 75 | #define PLOVER_GOODBYE_SOUND \ | ||
| 76 | E__NOTE(_GS6 ), \ | ||
| 77 | E__NOTE(_A6 ), \ | ||
| 78 | S__NOTE(_REST), \ | ||
| 79 | ED_NOTE(_A7 ), \ | ||
| 80 | S__NOTE(_REST), \ | ||
| 81 | ED_NOTE(_E7 ), | ||
| 82 | |||
| 83 | #define MUSIC_SCALE_SOUND \ | ||
| 84 | E__NOTE(_A5 ), \ | ||
| 85 | E__NOTE(_B5 ), \ | ||
| 86 | E__NOTE(_CS6), \ | ||
| 87 | E__NOTE(_D6 ), \ | ||
| 88 | E__NOTE(_E6 ), \ | ||
| 89 | E__NOTE(_FS6), \ | ||
| 90 | E__NOTE(_GS6), \ | ||
| 91 | E__NOTE(_A6 ), | ||
| 92 | |||
| 93 | #define CAPS_LOCK_ON_SOUND \ | ||
| 94 | E__NOTE(_A3), \ | ||
| 95 | E__NOTE(_B3), | ||
| 96 | |||
| 97 | #define CAPS_LOCK_OFF_SOUND \ | ||
| 98 | E__NOTE(_B3), \ | ||
| 99 | E__NOTE(_A3), | ||
| 100 | |||
| 101 | #define SCROLL_LOCK_ON_SOUND \ | ||
| 102 | E__NOTE(_D4), \ | ||
| 103 | E__NOTE(_E4), | ||
| 104 | |||
| 105 | #define SCROLL_LOCK_OFF_SOUND \ | ||
| 106 | E__NOTE(_E4), \ | ||
| 107 | E__NOTE(_D4), | ||
| 108 | |||
| 109 | #define NUM_LOCK_ON_SOUND \ | ||
| 110 | E__NOTE(_D5), \ | ||
| 111 | E__NOTE(_E5), | ||
| 112 | |||
| 113 | #define NUM_LOCK_OFF_SOUND \ | ||
| 114 | E__NOTE(_E5), \ | ||
| 115 | E__NOTE(_D5), | ||
| 116 | |||
| 117 | #endif | ||
diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c new file mode 100644 index 000000000..6d4172a06 --- /dev/null +++ b/quantum/audio/voices.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | #include "voices.h" | ||
| 2 | #include "audio.h" | ||
| 3 | #include "stdlib.h" | ||
| 4 | |||
| 5 | // these are imported from audio.c | ||
| 6 | extern uint16_t envelope_index; | ||
| 7 | extern float note_timbre; | ||
| 8 | extern float polyphony_rate; | ||
| 9 | |||
| 10 | voice_type voice = default_voice; | ||
| 11 | |||
| 12 | void set_voice(voice_type v) { | ||
| 13 | voice = v; | ||
| 14 | } | ||
| 15 | |||
| 16 | void voice_iterate() { | ||
| 17 | voice = (voice + 1) % number_of_voices; | ||
| 18 | } | ||
| 19 | |||
| 20 | void voice_deiterate() { | ||
| 21 | voice = (voice - 1) % number_of_voices; | ||
| 22 | } | ||
| 23 | |||
| 24 | float voice_envelope(float frequency) { | ||
| 25 | // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz | ||
| 26 | uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency)); | ||
| 27 | |||
| 28 | switch (voice) { | ||
| 29 | case default_voice: | ||
| 30 | note_timbre = TIMBRE_50; | ||
| 31 | polyphony_rate = 0; | ||
| 32 | break; | ||
| 33 | |||
| 34 | case butts_fader: | ||
| 35 | polyphony_rate = 0; | ||
| 36 | switch (compensated_index) { | ||
| 37 | case 0 ... 9: | ||
| 38 | frequency = frequency / 4; | ||
| 39 | note_timbre = TIMBRE_12; | ||
| 40 | break; | ||
| 41 | |||
| 42 | case 10 ... 19: | ||
| 43 | frequency = frequency / 2; | ||
| 44 | note_timbre = TIMBRE_12; | ||
| 45 | break; | ||
| 46 | |||
| 47 | case 20 ... 200: | ||
| 48 | note_timbre = .125 - pow(((float)compensated_index - 20) / (200 - 20), 2)*.125; | ||
| 49 | break; | ||
| 50 | |||
| 51 | default: | ||
| 52 | note_timbre = 0; | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | break; | ||
| 56 | |||
| 57 | // case octave_crunch: | ||
| 58 | // polyphony_rate = 0; | ||
| 59 | // switch (compensated_index) { | ||
| 60 | // case 0 ... 9: | ||
| 61 | // case 20 ... 24: | ||
| 62 | // case 30 ... 32: | ||
| 63 | // frequency = frequency / 2; | ||
| 64 | // note_timbre = TIMBRE_12; | ||
| 65 | // break; | ||
| 66 | |||
| 67 | // case 10 ... 19: | ||
| 68 | // case 25 ... 29: | ||
| 69 | // case 33 ... 35: | ||
| 70 | // frequency = frequency * 2; | ||
| 71 | // note_timbre = TIMBRE_12; | ||
| 72 | // break; | ||
| 73 | |||
| 74 | // default: | ||
| 75 | // note_timbre = TIMBRE_12; | ||
| 76 | // break; | ||
| 77 | // } | ||
| 78 | // break; | ||
| 79 | |||
| 80 | case duty_osc: | ||
| 81 | // This slows the loop down a substantial amount, so higher notes may freeze | ||
| 82 | polyphony_rate = 0; | ||
| 83 | switch (compensated_index) { | ||
| 84 | default: | ||
| 85 | #define OCS_SPEED 10 | ||
| 86 | #define OCS_AMP .25 | ||
| 87 | // sine wave is slow | ||
| 88 | // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5; | ||
| 89 | // triangle wave is a bit faster | ||
| 90 | note_timbre = (float)abs((compensated_index*OCS_SPEED % 3000) - 1500) * ( OCS_AMP / 1500 ) + (1 - OCS_AMP) / 2; | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | |||
| 95 | case duty_octave_down: | ||
| 96 | polyphony_rate = 0; | ||
| 97 | note_timbre = (envelope_index % 2) * .125 + .375 * 2; | ||
| 98 | if ((envelope_index % 4) == 0) | ||
| 99 | note_timbre = 0.5; | ||
| 100 | if ((envelope_index % 8) == 0) | ||
| 101 | note_timbre = 0; | ||
| 102 | break; | ||
| 103 | case delayed_vibrato: | ||
| 104 | polyphony_rate = 0; | ||
| 105 | note_timbre = TIMBRE_50; | ||
| 106 | #define VOICE_VIBRATO_DELAY 150 | ||
| 107 | #define VOICE_VIBRATO_SPEED 50 | ||
| 108 | switch (compensated_index) { | ||
| 109 | case 0 ... VOICE_VIBRATO_DELAY: | ||
| 110 | break; | ||
| 111 | default: | ||
| 112 | frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | break; | ||
| 116 | // case delayed_vibrato_octave: | ||
| 117 | // polyphony_rate = 0; | ||
| 118 | // if ((envelope_index % 2) == 1) { | ||
| 119 | // note_timbre = 0.55; | ||
| 120 | // } else { | ||
| 121 | // note_timbre = 0.45; | ||
| 122 | // } | ||
| 123 | // #define VOICE_VIBRATO_DELAY 150 | ||
| 124 | // #define VOICE_VIBRATO_SPEED 50 | ||
| 125 | // switch (compensated_index) { | ||
| 126 | // case 0 ... VOICE_VIBRATO_DELAY: | ||
| 127 | // break; | ||
| 128 | // default: | ||
| 129 | // frequency = frequency * VIBRATO_LUT[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; | ||
| 130 | // break; | ||
| 131 | // } | ||
| 132 | // break; | ||
| 133 | // case duty_fifth_down: | ||
| 134 | // note_timbre = 0.5; | ||
| 135 | // if ((envelope_index % 3) == 0) | ||
| 136 | // note_timbre = 0.75; | ||
| 137 | // break; | ||
| 138 | // case duty_fourth_down: | ||
| 139 | // note_timbre = 0.0; | ||
| 140 | // if ((envelope_index % 12) == 0) | ||
| 141 | // note_timbre = 0.75; | ||
| 142 | // if (((envelope_index % 12) % 4) != 1) | ||
| 143 | // note_timbre = 0.75; | ||
| 144 | // break; | ||
| 145 | // case duty_third_down: | ||
| 146 | // note_timbre = 0.5; | ||
| 147 | // if ((envelope_index % 5) == 0) | ||
| 148 | // note_timbre = 0.75; | ||
| 149 | // break; | ||
| 150 | // case duty_fifth_third_down: | ||
| 151 | // note_timbre = 0.5; | ||
| 152 | // if ((envelope_index % 5) == 0) | ||
| 153 | // note_timbre = 0.75; | ||
| 154 | // if ((envelope_index % 3) == 0) | ||
| 155 | // note_timbre = 0.25; | ||
| 156 | // break; | ||
| 157 | |||
| 158 | default: | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | |||
| 162 | return frequency; | ||
| 163 | } | ||
| 164 | |||
| 165 | |||
diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h new file mode 100644 index 000000000..b2495b23b --- /dev/null +++ b/quantum/audio/voices.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #include <stdint.h> | ||
| 2 | #include <stdbool.h> | ||
| 3 | #include <avr/io.h> | ||
| 4 | #include <util/delay.h> | ||
| 5 | #include "luts.h" | ||
| 6 | |||
| 7 | #ifndef VOICES_H | ||
| 8 | #define VOICES_H | ||
| 9 | |||
| 10 | float voice_envelope(float frequency); | ||
| 11 | |||
| 12 | typedef enum { | ||
| 13 | default_voice, | ||
| 14 | butts_fader, | ||
| 15 | octave_crunch, | ||
| 16 | duty_osc, | ||
| 17 | duty_octave_down, | ||
| 18 | delayed_vibrato, | ||
| 19 | // delayed_vibrato_octave, | ||
| 20 | // duty_fifth_down, | ||
| 21 | // duty_fourth_down, | ||
| 22 | // duty_third_down, | ||
| 23 | // duty_fifth_third_down, | ||
| 24 | number_of_voices // important that this is last | ||
| 25 | } voice_type; | ||
| 26 | |||
| 27 | void set_voice(voice_type v); | ||
| 28 | void voice_iterate(void); | ||
| 29 | void voice_deiterate(void); | ||
| 30 | |||
| 31 | #endif \ No newline at end of file | ||
diff --git a/quantum/audio/wave.h b/quantum/audio/wave.h new file mode 100644 index 000000000..6ebc34851 --- /dev/null +++ b/quantum/audio/wave.h | |||
| @@ -0,0 +1,265 @@ | |||
| 1 | #include <avr/io.h> | ||
| 2 | #include <avr/interrupt.h> | ||
| 3 | #include <avr/pgmspace.h> | ||
| 4 | |||
| 5 | #define SINE_LENGTH 2048 | ||
| 6 | |||
| 7 | const uint8_t sinewave[] PROGMEM= //2048 values | ||
| 8 | { | ||
| 9 | 0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82, | ||
| 10 | 0x83,0x83,0x83,0x84,0x84,0x85,0x85,0x85, | ||
| 11 | 0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88, | ||
| 12 | 0x89,0x89,0x8a,0x8a,0x8a,0x8b,0x8b,0x8c, | ||
| 13 | 0x8c,0x8c,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f, | ||
| 14 | 0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92, | ||
| 15 | 0x92,0x93,0x93,0x93,0x94,0x94,0x95,0x95, | ||
| 16 | 0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98, | ||
| 17 | 0x98,0x99,0x99,0x9a,0x9a,0x9a,0x9b,0x9b, | ||
| 18 | 0x9b,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e, | ||
| 19 | 0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1, | ||
| 20 | 0xa2,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4, | ||
| 21 | 0xa5,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7, | ||
| 22 | 0xa7,0xa8,0xa8,0xa9,0xa9,0xa9,0xaa,0xaa, | ||
| 23 | 0xaa,0xab,0xab,0xac,0xac,0xac,0xad,0xad, | ||
| 24 | 0xad,0xae,0xae,0xae,0xaf,0xaf,0xb0,0xb0, | ||
| 25 | 0xb0,0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb3, | ||
| 26 | 0xb3,0xb4,0xb4,0xb4,0xb5,0xb5,0xb5,0xb6, | ||
| 27 | 0xb6,0xb6,0xb7,0xb7,0xb7,0xb8,0xb8,0xb8, | ||
| 28 | 0xb9,0xb9,0xba,0xba,0xba,0xbb,0xbb,0xbb, | ||
| 29 | 0xbc,0xbc,0xbc,0xbd,0xbd,0xbd,0xbe,0xbe, | ||
| 30 | 0xbe,0xbf,0xbf,0xbf,0xc0,0xc0,0xc0,0xc1, | ||
| 31 | 0xc1,0xc1,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3, | ||
| 32 | 0xc4,0xc4,0xc4,0xc5,0xc5,0xc5,0xc6,0xc6, | ||
| 33 | 0xc6,0xc7,0xc7,0xc7,0xc8,0xc8,0xc8,0xc9, | ||
| 34 | 0xc9,0xc9,0xca,0xca,0xca,0xcb,0xcb,0xcb, | ||
| 35 | 0xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce, | ||
| 36 | 0xce,0xce,0xcf,0xcf,0xcf,0xcf,0xd0,0xd0, | ||
| 37 | 0xd0,0xd1,0xd1,0xd1,0xd2,0xd2,0xd2,0xd2, | ||
| 38 | 0xd3,0xd3,0xd3,0xd4,0xd4,0xd4,0xd5,0xd5, | ||
| 39 | 0xd5,0xd5,0xd6,0xd6,0xd6,0xd7,0xd7,0xd7, | ||
| 40 | 0xd7,0xd8,0xd8,0xd8,0xd9,0xd9,0xd9,0xd9, | ||
| 41 | 0xda,0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdc, | ||
| 42 | 0xdc,0xdc,0xdc,0xdd,0xdd,0xdd,0xdd,0xde, | ||
| 43 | 0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xe0, | ||
| 44 | 0xe0,0xe0,0xe1,0xe1,0xe1,0xe1,0xe2,0xe2, | ||
| 45 | 0xe2,0xe2,0xe3,0xe3,0xe3,0xe3,0xe4,0xe4, | ||
| 46 | 0xe4,0xe4,0xe4,0xe5,0xe5,0xe5,0xe5,0xe6, | ||
| 47 | 0xe6,0xe6,0xe6,0xe7,0xe7,0xe7,0xe7,0xe8, | ||
| 48 | 0xe8,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xe9, | ||
| 49 | 0xea,0xea,0xea,0xea,0xea,0xeb,0xeb,0xeb, | ||
| 50 | 0xeb,0xeb,0xec,0xec,0xec,0xec,0xec,0xed, | ||
| 51 | 0xed,0xed,0xed,0xed,0xee,0xee,0xee,0xee, | ||
| 52 | 0xee,0xef,0xef,0xef,0xef,0xef,0xf0,0xf0, | ||
| 53 | 0xf0,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf1, | ||
| 54 | 0xf1,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf3, | ||
| 55 | 0xf3,0xf3,0xf3,0xf3,0xf3,0xf4,0xf4,0xf4, | ||
| 56 | 0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5, | ||
| 57 | 0xf5,0xf5,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, | ||
| 58 | 0xf6,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, | ||
| 59 | 0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, | ||
| 60 | 0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, | ||
| 61 | 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, | ||
| 62 | 0xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb, | ||
| 63 | 0xfb,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfc, | ||
| 64 | 0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, | ||
| 65 | 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, | ||
| 66 | 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfe,0xfe, | ||
| 67 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
| 68 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
| 69 | 0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff, | ||
| 70 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
| 71 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
| 72 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
| 73 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
| 74 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
| 75 | 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, | ||
| 76 | 0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe, | ||
| 77 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
| 78 | 0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, | ||
| 79 | 0xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfd,0xfd, | ||
| 80 | 0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, | ||
| 81 | 0xfd,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, | ||
| 82 | 0xfc,0xfc,0xfc,0xfc,0xfc,0xfb,0xfb,0xfb, | ||
| 83 | 0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfa, | ||
| 84 | 0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, | ||
| 85 | 0xfa,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, | ||
| 86 | 0xf9,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, | ||
| 87 | 0xf8,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, | ||
| 88 | 0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf5, | ||
| 89 | 0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf4,0xf4, | ||
| 90 | 0xf4,0xf4,0xf4,0xf4,0xf3,0xf3,0xf3,0xf3, | ||
| 91 | 0xf3,0xf3,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2, | ||
| 92 | 0xf1,0xf1,0xf1,0xf1,0xf1,0xf0,0xf0,0xf0, | ||
| 93 | 0xf0,0xf0,0xf0,0xef,0xef,0xef,0xef,0xef, | ||
| 94 | 0xee,0xee,0xee,0xee,0xee,0xed,0xed,0xed, | ||
| 95 | 0xed,0xed,0xec,0xec,0xec,0xec,0xec,0xeb, | ||
| 96 | 0xeb,0xeb,0xeb,0xeb,0xea,0xea,0xea,0xea, | ||
| 97 | 0xea,0xe9,0xe9,0xe9,0xe9,0xe8,0xe8,0xe8, | ||
| 98 | 0xe8,0xe8,0xe7,0xe7,0xe7,0xe7,0xe6,0xe6, | ||
| 99 | 0xe6,0xe6,0xe5,0xe5,0xe5,0xe5,0xe4,0xe4, | ||
| 100 | 0xe4,0xe4,0xe4,0xe3,0xe3,0xe3,0xe3,0xe2, | ||
| 101 | 0xe2,0xe2,0xe2,0xe1,0xe1,0xe1,0xe1,0xe0, | ||
| 102 | 0xe0,0xe0,0xe0,0xdf,0xdf,0xdf,0xde,0xde, | ||
| 103 | 0xde,0xde,0xdd,0xdd,0xdd,0xdd,0xdc,0xdc, | ||
| 104 | 0xdc,0xdc,0xdb,0xdb,0xdb,0xda,0xda,0xda, | ||
| 105 | 0xda,0xd9,0xd9,0xd9,0xd9,0xd8,0xd8,0xd8, | ||
| 106 | 0xd7,0xd7,0xd7,0xd7,0xd6,0xd6,0xd6,0xd5, | ||
| 107 | 0xd5,0xd5,0xd5,0xd4,0xd4,0xd4,0xd3,0xd3, | ||
| 108 | 0xd3,0xd2,0xd2,0xd2,0xd2,0xd1,0xd1,0xd1, | ||
| 109 | 0xd0,0xd0,0xd0,0xcf,0xcf,0xcf,0xcf,0xce, | ||
| 110 | 0xce,0xce,0xcd,0xcd,0xcd,0xcc,0xcc,0xcc, | ||
| 111 | 0xcb,0xcb,0xcb,0xcb,0xca,0xca,0xca,0xc9, | ||
| 112 | 0xc9,0xc9,0xc8,0xc8,0xc8,0xc7,0xc7,0xc7, | ||
| 113 | 0xc6,0xc6,0xc6,0xc5,0xc5,0xc5,0xc4,0xc4, | ||
| 114 | 0xc4,0xc3,0xc3,0xc3,0xc2,0xc2,0xc2,0xc1, | ||
| 115 | 0xc1,0xc1,0xc0,0xc0,0xc0,0xbf,0xbf,0xbf, | ||
| 116 | 0xbe,0xbe,0xbe,0xbd,0xbd,0xbd,0xbc,0xbc, | ||
| 117 | 0xbc,0xbb,0xbb,0xbb,0xba,0xba,0xba,0xb9, | ||
| 118 | 0xb9,0xb8,0xb8,0xb8,0xb7,0xb7,0xb7,0xb6, | ||
| 119 | 0xb6,0xb6,0xb5,0xb5,0xb5,0xb4,0xb4,0xb4, | ||
| 120 | 0xb3,0xb3,0xb2,0xb2,0xb2,0xb1,0xb1,0xb1, | ||
| 121 | 0xb0,0xb0,0xb0,0xaf,0xaf,0xae,0xae,0xae, | ||
| 122 | 0xad,0xad,0xad,0xac,0xac,0xac,0xab,0xab, | ||
| 123 | 0xaa,0xaa,0xaa,0xa9,0xa9,0xa9,0xa8,0xa8, | ||
| 124 | 0xa7,0xa7,0xa7,0xa6,0xa6,0xa6,0xa5,0xa5, | ||
| 125 | 0xa5,0xa4,0xa4,0xa3,0xa3,0xa3,0xa2,0xa2, | ||
| 126 | 0xa2,0xa1,0xa1,0xa0,0xa0,0xa0,0x9f,0x9f, | ||
| 127 | 0x9e,0x9e,0x9e,0x9d,0x9d,0x9d,0x9c,0x9c, | ||
| 128 | 0x9b,0x9b,0x9b,0x9a,0x9a,0x9a,0x99,0x99, | ||
| 129 | 0x98,0x98,0x98,0x97,0x97,0x96,0x96,0x96, | ||
| 130 | 0x95,0x95,0x95,0x94,0x94,0x93,0x93,0x93, | ||
| 131 | 0x92,0x92,0x91,0x91,0x91,0x90,0x90,0x8f, | ||
| 132 | 0x8f,0x8f,0x8e,0x8e,0x8e,0x8d,0x8d,0x8c, | ||
| 133 | 0x8c,0x8c,0x8b,0x8b,0x8a,0x8a,0x8a,0x89, | ||
| 134 | 0x89,0x88,0x88,0x88,0x87,0x87,0x87,0x86, | ||
| 135 | 0x86,0x85,0x85,0x85,0x84,0x84,0x83,0x83, | ||
| 136 | 0x83,0x82,0x82,0x81,0x81,0x81,0x80,0x80, | ||
| 137 | 0x80,0x7f,0x7f,0x7e,0x7e,0x7e,0x7d,0x7d, | ||
| 138 | 0x7c,0x7c,0x7c,0x7b,0x7b,0x7a,0x7a,0x7a, | ||
| 139 | 0x79,0x79,0x78,0x78,0x78,0x77,0x77,0x77, | ||
| 140 | 0x76,0x76,0x75,0x75,0x75,0x74,0x74,0x73, | ||
| 141 | 0x73,0x73,0x72,0x72,0x71,0x71,0x71,0x70, | ||
| 142 | 0x70,0x70,0x6f,0x6f,0x6e,0x6e,0x6e,0x6d, | ||
| 143 | 0x6d,0x6c,0x6c,0x6c,0x6b,0x6b,0x6a,0x6a, | ||
| 144 | 0x6a,0x69,0x69,0x69,0x68,0x68,0x67,0x67, | ||
| 145 | 0x67,0x66,0x66,0x65,0x65,0x65,0x64,0x64, | ||
| 146 | 0x64,0x63,0x63,0x62,0x62,0x62,0x61,0x61, | ||
| 147 | 0x61,0x60,0x60,0x5f,0x5f,0x5f,0x5e,0x5e, | ||
| 148 | 0x5d,0x5d,0x5d,0x5c,0x5c,0x5c,0x5b,0x5b, | ||
| 149 | 0x5a,0x5a,0x5a,0x59,0x59,0x59,0x58,0x58, | ||
| 150 | 0x58,0x57,0x57,0x56,0x56,0x56,0x55,0x55, | ||
| 151 | 0x55,0x54,0x54,0x53,0x53,0x53,0x52,0x52, | ||
| 152 | 0x52,0x51,0x51,0x51,0x50,0x50,0x4f,0x4f, | ||
| 153 | 0x4f,0x4e,0x4e,0x4e,0x4d,0x4d,0x4d,0x4c, | ||
| 154 | 0x4c,0x4b,0x4b,0x4b,0x4a,0x4a,0x4a,0x49, | ||
| 155 | 0x49,0x49,0x48,0x48,0x48,0x47,0x47,0x47, | ||
| 156 | 0x46,0x46,0x45,0x45,0x45,0x44,0x44,0x44, | ||
| 157 | 0x43,0x43,0x43,0x42,0x42,0x42,0x41,0x41, | ||
| 158 | 0x41,0x40,0x40,0x40,0x3f,0x3f,0x3f,0x3e, | ||
| 159 | 0x3e,0x3e,0x3d,0x3d,0x3d,0x3c,0x3c,0x3c, | ||
| 160 | 0x3b,0x3b,0x3b,0x3a,0x3a,0x3a,0x39,0x39, | ||
| 161 | 0x39,0x38,0x38,0x38,0x37,0x37,0x37,0x36, | ||
| 162 | 0x36,0x36,0x35,0x35,0x35,0x34,0x34,0x34, | ||
| 163 | 0x34,0x33,0x33,0x33,0x32,0x32,0x32,0x31, | ||
| 164 | 0x31,0x31,0x30,0x30,0x30,0x30,0x2f,0x2f, | ||
| 165 | 0x2f,0x2e,0x2e,0x2e,0x2d,0x2d,0x2d,0x2d, | ||
| 166 | 0x2c,0x2c,0x2c,0x2b,0x2b,0x2b,0x2a,0x2a, | ||
| 167 | 0x2a,0x2a,0x29,0x29,0x29,0x28,0x28,0x28, | ||
| 168 | 0x28,0x27,0x27,0x27,0x26,0x26,0x26,0x26, | ||
| 169 | 0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x23, | ||
| 170 | 0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x21, | ||
| 171 | 0x21,0x21,0x21,0x20,0x20,0x20,0x1f,0x1f, | ||
| 172 | 0x1f,0x1f,0x1e,0x1e,0x1e,0x1e,0x1d,0x1d, | ||
| 173 | 0x1d,0x1d,0x1c,0x1c,0x1c,0x1c,0x1b,0x1b, | ||
| 174 | 0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x19, | ||
| 175 | 0x19,0x19,0x19,0x18,0x18,0x18,0x18,0x17, | ||
| 176 | 0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16, | ||
| 177 | 0x15,0x15,0x15,0x15,0x15,0x14,0x14,0x14, | ||
| 178 | 0x14,0x14,0x13,0x13,0x13,0x13,0x13,0x12, | ||
| 179 | 0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11, | ||
| 180 | 0x11,0x10,0x10,0x10,0x10,0x10,0xf,0xf, | ||
| 181 | 0xf,0xf,0xf,0xf,0xe,0xe,0xe,0xe, | ||
| 182 | 0xe,0xd,0xd,0xd,0xd,0xd,0xd,0xc, | ||
| 183 | 0xc,0xc,0xc,0xc,0xc,0xb,0xb,0xb, | ||
| 184 | 0xb,0xb,0xb,0xa,0xa,0xa,0xa,0xa, | ||
| 185 | 0xa,0xa,0x9,0x9,0x9,0x9,0x9,0x9, | ||
| 186 | 0x9,0x8,0x8,0x8,0x8,0x8,0x8,0x8, | ||
| 187 | 0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7, | ||
| 188 | 0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x6, | ||
| 189 | 0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5, | ||
| 190 | 0x5,0x5,0x4,0x4,0x4,0x4,0x4,0x4, | ||
| 191 | 0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3, | ||
| 192 | 0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3, | ||
| 193 | 0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, | ||
| 194 | 0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x1, | ||
| 195 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
| 196 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
| 197 | 0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0, | ||
| 198 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
| 199 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
| 200 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
| 201 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
| 202 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
| 203 | 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, | ||
| 204 | 0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1, | ||
| 205 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
| 206 | 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, | ||
| 207 | 0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2, | ||
| 208 | 0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, | ||
| 209 | 0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3, | ||
| 210 | 0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4, | ||
| 211 | 0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5, | ||
| 212 | 0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5, | ||
| 213 | 0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6, | ||
| 214 | 0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x7, | ||
| 215 | 0x7,0x8,0x8,0x8,0x8,0x8,0x8,0x8, | ||
| 216 | 0x9,0x9,0x9,0x9,0x9,0x9,0x9,0xa, | ||
| 217 | 0xa,0xa,0xa,0xa,0xa,0xa,0xb,0xb, | ||
| 218 | 0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc, | ||
| 219 | 0xc,0xc,0xd,0xd,0xd,0xd,0xd,0xd, | ||
| 220 | 0xe,0xe,0xe,0xe,0xe,0xf,0xf,0xf, | ||
| 221 | 0xf,0xf,0xf,0x10,0x10,0x10,0x10,0x10, | ||
| 222 | 0x11,0x11,0x11,0x11,0x11,0x12,0x12,0x12, | ||
| 223 | 0x12,0x12,0x13,0x13,0x13,0x13,0x13,0x14, | ||
| 224 | 0x14,0x14,0x14,0x14,0x15,0x15,0x15,0x15, | ||
| 225 | 0x15,0x16,0x16,0x16,0x16,0x17,0x17,0x17, | ||
| 226 | 0x17,0x17,0x18,0x18,0x18,0x18,0x19,0x19, | ||
| 227 | 0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1b,0x1b, | ||
| 228 | 0x1b,0x1b,0x1b,0x1c,0x1c,0x1c,0x1c,0x1d, | ||
| 229 | 0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x1e,0x1f, | ||
| 230 | 0x1f,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21, | ||
| 231 | 0x21,0x21,0x22,0x22,0x22,0x22,0x23,0x23, | ||
| 232 | 0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x25, | ||
| 233 | 0x25,0x26,0x26,0x26,0x26,0x27,0x27,0x27, | ||
| 234 | 0x28,0x28,0x28,0x28,0x29,0x29,0x29,0x2a, | ||
| 235 | 0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,0x2c,0x2c, | ||
| 236 | 0x2c,0x2d,0x2d,0x2d,0x2d,0x2e,0x2e,0x2e, | ||
| 237 | 0x2f,0x2f,0x2f,0x30,0x30,0x30,0x30,0x31, | ||
| 238 | 0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x33, | ||
| 239 | 0x34,0x34,0x34,0x34,0x35,0x35,0x35,0x36, | ||
| 240 | 0x36,0x36,0x37,0x37,0x37,0x38,0x38,0x38, | ||
| 241 | 0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b, | ||
| 242 | 0x3b,0x3c,0x3c,0x3c,0x3d,0x3d,0x3d,0x3e, | ||
| 243 | 0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40, | ||
| 244 | 0x41,0x41,0x41,0x42,0x42,0x42,0x43,0x43, | ||
| 245 | 0x43,0x44,0x44,0x44,0x45,0x45,0x45,0x46, | ||
| 246 | 0x46,0x47,0x47,0x47,0x48,0x48,0x48,0x49, | ||
| 247 | 0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b, | ||
| 248 | 0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4e, | ||
| 249 | 0x4f,0x4f,0x4f,0x50,0x50,0x51,0x51,0x51, | ||
| 250 | 0x52,0x52,0x52,0x53,0x53,0x53,0x54,0x54, | ||
| 251 | 0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57, | ||
| 252 | 0x58,0x58,0x58,0x59,0x59,0x59,0x5a,0x5a, | ||
| 253 | 0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d, | ||
| 254 | 0x5d,0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60, | ||
| 255 | 0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, | ||
| 256 | 0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66, | ||
| 257 | 0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x69, | ||
| 258 | 0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c, | ||
| 259 | 0x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x70, | ||
| 260 | 0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x73, | ||
| 261 | 0x73,0x73,0x74,0x74,0x75,0x75,0x75,0x76, | ||
| 262 | 0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79, | ||
| 263 | 0x79,0x7a,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c, | ||
| 264 | 0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f | ||
| 265 | }; \ No newline at end of file | ||
diff --git a/quantum/config_common.h b/quantum/config_common.h new file mode 100644 index 000000000..09a4fe701 --- /dev/null +++ b/quantum/config_common.h | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | #ifndef CONFIG_DEFINITIONS_H | ||
| 2 | #define CONFIG_DEFINITIONS_H | ||
| 3 | |||
| 4 | /* diode directions */ | ||
| 5 | #define COL2ROW 0 | ||
| 6 | #define ROW2COL 1 | ||
| 7 | /* I/O pins */ | ||
| 8 | #define B0 0x30 | ||
| 9 | #define B1 0x31 | ||
| 10 | #define B2 0x32 | ||
| 11 | #define B3 0x33 | ||
| 12 | #define B4 0x34 | ||
| 13 | #define B5 0x35 | ||
| 14 | #define B6 0x36 | ||
| 15 | #define B7 0x37 | ||
| 16 | #define C0 0x60 | ||
| 17 | #define C1 0x61 | ||
| 18 | #define C2 0x62 | ||
| 19 | #define C3 0x63 | ||
| 20 | #define C4 0x64 | ||
| 21 | #define C5 0x65 | ||
| 22 | #define C6 0x66 | ||
| 23 | #define C7 0x67 | ||
| 24 | #define D0 0x90 | ||
| 25 | #define D1 0x91 | ||
| 26 | #define D2 0x92 | ||
| 27 | #define D3 0x93 | ||
| 28 | #define D4 0x94 | ||
| 29 | #define D5 0x95 | ||
| 30 | #define D6 0x96 | ||
| 31 | #define D7 0x97 | ||
| 32 | #define E0 0xC0 | ||
| 33 | #define E1 0xC1 | ||
| 34 | #define E2 0xC2 | ||
| 35 | #define E3 0xC3 | ||
| 36 | #define E4 0xC4 | ||
| 37 | #define E5 0xC5 | ||
| 38 | #define E6 0xC6 | ||
| 39 | #define E7 0xC7 | ||
| 40 | #define F0 0xF0 | ||
| 41 | #define F1 0xF1 | ||
| 42 | #define F2 0xF2 | ||
| 43 | #define F3 0xF3 | ||
| 44 | #define F4 0xF4 | ||
| 45 | #define F5 0xF5 | ||
| 46 | #define F6 0xF6 | ||
| 47 | #define F7 0xF7 | ||
| 48 | |||
| 49 | /* USART configuration */ | ||
| 50 | #ifdef BLUETOOTH_ENABLE | ||
| 51 | # ifdef __AVR_ATmega32U4__ | ||
| 52 | # define SERIAL_UART_BAUD 9600 | ||
| 53 | # define SERIAL_UART_DATA UDR1 | ||
| 54 | # define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1) | ||
| 55 | # define SERIAL_UART_RXD_VECT USART1_RX_vect | ||
| 56 | # define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1)) | ||
| 57 | # define SERIAL_UART_INIT() do { \ | ||
| 58 | /* baud rate */ \ | ||
| 59 | UBRR1L = SERIAL_UART_UBRR; \ | ||
| 60 | /* baud rate */ \ | ||
| 61 | UBRR1H = SERIAL_UART_UBRR >> 8; \ | ||
| 62 | /* enable TX */ \ | ||
| 63 | UCSR1B = _BV(TXEN1); \ | ||
| 64 | /* 8-bit data */ \ | ||
| 65 | UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \ | ||
| 66 | sei(); \ | ||
| 67 | } while(0) | ||
| 68 | # else | ||
| 69 | # error "USART configuration is needed." | ||
| 70 | #endif | ||
| 71 | |||
| 72 | // I'm fairly sure these aren't needed, but oh well - Jack | ||
| 73 | |||
| 74 | /* | ||
| 75 | * PS/2 Interrupt configuration | ||
| 76 | */ | ||
| 77 | #ifdef PS2_USE_INT | ||
| 78 | /* uses INT1 for clock line(ATMega32U4) */ | ||
| 79 | #define PS2_CLOCK_PORT PORTD | ||
| 80 | #define PS2_CLOCK_PIN PIND | ||
| 81 | #define PS2_CLOCK_DDR DDRD | ||
| 82 | #define PS2_CLOCK_BIT 1 | ||
| 83 | |||
| 84 | #define PS2_DATA_PORT PORTD | ||
| 85 | #define PS2_DATA_PIN PIND | ||
| 86 | #define PS2_DATA_DDR DDRD | ||
| 87 | #define PS2_DATA_BIT 0 | ||
| 88 | |||
| 89 | #define PS2_INT_INIT() do { \ | ||
| 90 | EICRA |= ((1<<ISC11) | \ | ||
| 91 | (0<<ISC10)); \ | ||
| 92 | } while (0) | ||
| 93 | #define PS2_INT_ON() do { \ | ||
| 94 | EIMSK |= (1<<INT1); \ | ||
| 95 | } while (0) | ||
| 96 | #define PS2_INT_OFF() do { \ | ||
| 97 | EIMSK &= ~(1<<INT1); \ | ||
| 98 | } while (0) | ||
| 99 | #define PS2_INT_VECT INT1_vect | ||
| 100 | #endif | ||
| 101 | |||
| 102 | /* | ||
| 103 | * PS/2 Busywait configuration | ||
| 104 | */ | ||
| 105 | #ifdef PS2_USE_BUSYWAIT | ||
| 106 | #define PS2_CLOCK_PORT PORTD | ||
| 107 | #define PS2_CLOCK_PIN PIND | ||
| 108 | #define PS2_CLOCK_DDR DDRD | ||
| 109 | #define PS2_CLOCK_BIT 1 | ||
| 110 | |||
| 111 | #define PS2_DATA_PORT PORTD | ||
| 112 | #define PS2_DATA_PIN PIND | ||
| 113 | #define PS2_DATA_DDR DDRD | ||
| 114 | #define PS2_DATA_BIT 0 | ||
| 115 | #endif | ||
| 116 | |||
| 117 | #endif | ||
| 118 | |||
| 119 | #endif | ||
diff --git a/quantum/keycode_config.c b/quantum/keycode_config.c new file mode 100644 index 000000000..6d90781a1 --- /dev/null +++ b/quantum/keycode_config.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #include "keycode_config.h" | ||
| 2 | |||
| 3 | extern keymap_config_t keymap_config; | ||
| 4 | |||
| 5 | uint16_t keycode_config(uint16_t keycode) { | ||
| 6 | |||
| 7 | switch (keycode) { | ||
| 8 | case KC_CAPSLOCK: | ||
| 9 | case KC_LOCKING_CAPS: | ||
| 10 | if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) { | ||
| 11 | return KC_LCTL; | ||
| 12 | } | ||
| 13 | return keycode; | ||
| 14 | case KC_LCTL: | ||
| 15 | if (keymap_config.swap_control_capslock) { | ||
| 16 | return KC_CAPSLOCK; | ||
| 17 | } | ||
| 18 | return KC_LCTL; | ||
| 19 | case KC_LALT: | ||
| 20 | if (keymap_config.swap_lalt_lgui) { | ||
| 21 | if (keymap_config.no_gui) { | ||
| 22 | return KC_NO; | ||
| 23 | } | ||
| 24 | return KC_LGUI; | ||
| 25 | } | ||
| 26 | return KC_LALT; | ||
| 27 | case KC_LGUI: | ||
| 28 | if (keymap_config.swap_lalt_lgui) { | ||
| 29 | return KC_LALT; | ||
| 30 | } | ||
| 31 | if (keymap_config.no_gui) { | ||
| 32 | return KC_NO; | ||
| 33 | } | ||
| 34 | return KC_LGUI; | ||
| 35 | case KC_RALT: | ||
| 36 | if (keymap_config.swap_ralt_rgui) { | ||
| 37 | if (keymap_config.no_gui) { | ||
| 38 | return KC_NO; | ||
| 39 | } | ||
| 40 | return KC_RGUI; | ||
| 41 | } | ||
| 42 | return KC_RALT; | ||
| 43 | case KC_RGUI: | ||
| 44 | if (keymap_config.swap_ralt_rgui) { | ||
| 45 | return KC_RALT; | ||
| 46 | } | ||
| 47 | if (keymap_config.no_gui) { | ||
| 48 | return KC_NO; | ||
| 49 | } | ||
| 50 | return KC_RGUI; | ||
| 51 | case KC_GRAVE: | ||
| 52 | if (keymap_config.swap_grave_esc) { | ||
| 53 | return KC_ESC; | ||
| 54 | } | ||
| 55 | return KC_GRAVE; | ||
| 56 | case KC_ESC: | ||
| 57 | if (keymap_config.swap_grave_esc) { | ||
| 58 | return KC_GRAVE; | ||
| 59 | } | ||
| 60 | return KC_ESC; | ||
| 61 | case KC_BSLASH: | ||
| 62 | if (keymap_config.swap_backslash_backspace) { | ||
| 63 | return KC_BSPACE; | ||
| 64 | } | ||
| 65 | return KC_BSLASH; | ||
| 66 | case KC_BSPACE: | ||
| 67 | if (keymap_config.swap_backslash_backspace) { | ||
| 68 | return KC_BSLASH; | ||
| 69 | } | ||
| 70 | return KC_BSPACE; | ||
| 71 | default: | ||
| 72 | return keycode; | ||
| 73 | } | ||
| 74 | } \ No newline at end of file | ||
diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h new file mode 100644 index 000000000..6216eefc9 --- /dev/null +++ b/quantum/keycode_config.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #include "eeconfig.h" | ||
| 2 | #include "keycode.h" | ||
| 3 | |||
| 4 | uint16_t keycode_config(uint16_t keycode); | ||
| 5 | |||
| 6 | /* NOTE: Not portable. Bit field order depends on implementation */ | ||
| 7 | typedef union { | ||
| 8 | uint16_t raw; | ||
| 9 | struct { | ||
| 10 | bool swap_control_capslock:1; | ||
| 11 | bool capslock_to_control:1; | ||
| 12 | bool swap_lalt_lgui:1; | ||
| 13 | bool swap_ralt_rgui:1; | ||
| 14 | bool no_gui:1; | ||
| 15 | bool swap_grave_esc:1; | ||
| 16 | bool swap_backslash_backspace:1; | ||
| 17 | bool nkro:1; | ||
| 18 | }; | ||
| 19 | } keymap_config_t; | ||
| 20 | |||
| 21 | extern keymap_config_t keymap_config; | ||
diff --git a/quantum/keymap.h b/quantum/keymap.h new file mode 100644 index 000000000..73f99f821 --- /dev/null +++ b/quantum/keymap.h | |||
| @@ -0,0 +1,328 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2012,2013 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef KEYMAP_H | ||
| 19 | #define KEYMAP_H | ||
| 20 | |||
| 21 | #include <stdint.h> | ||
| 22 | #include <stdbool.h> | ||
| 23 | #include "action.h" | ||
| 24 | #if defined(__AVR__) | ||
| 25 | #include <avr/pgmspace.h> | ||
| 26 | #endif | ||
| 27 | #include "keycode.h" | ||
| 28 | #include "action_macro.h" | ||
| 29 | #include "report.h" | ||
| 30 | #include "host.h" | ||
| 31 | // #include "print.h" | ||
| 32 | #include "debug.h" | ||
| 33 | #include "keycode_config.h" | ||
| 34 | |||
| 35 | // ChibiOS uses RESET in its FlagStatus enumeration | ||
| 36 | // Therefore define it as QK_RESET here, to avoid name collision | ||
| 37 | #if defined(PROTOCOL_CHIBIOS) | ||
| 38 | #define RESET QK_RESET | ||
| 39 | #endif | ||
| 40 | |||
| 41 | /* translates key to keycode */ | ||
| 42 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); | ||
| 43 | |||
| 44 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | ||
| 45 | extern const uint16_t fn_actions[]; | ||
| 46 | |||
| 47 | enum quantum_keycodes { | ||
| 48 | // Ranges used in shortucuts - not to be used directly | ||
| 49 | QK_TMK = 0x0000, | ||
| 50 | QK_TMK_MAX = 0x00FF, | ||
| 51 | QK_MODS = 0x0100, | ||
| 52 | QK_LCTL = 0x0100, | ||
| 53 | QK_LSFT = 0x0200, | ||
| 54 | QK_LALT = 0x0400, | ||
| 55 | QK_LGUI = 0x0800, | ||
| 56 | QK_RCTL = 0x1100, | ||
| 57 | QK_RSFT = 0x1200, | ||
| 58 | QK_RALT = 0x1400, | ||
| 59 | QK_RGUI = 0x1800, | ||
| 60 | QK_MODS_MAX = 0x1FFF, | ||
| 61 | QK_FUNCTION = 0x2000, | ||
| 62 | QK_FUNCTION_MAX = 0x2FFF, | ||
| 63 | QK_MACRO = 0x3000, | ||
| 64 | QK_MACRO_MAX = 0x3FFF, | ||
| 65 | QK_LAYER_TAP = 0x4000, | ||
| 66 | QK_LAYER_TAP_MAX = 0x4FFF, | ||
| 67 | QK_TO = 0x5000, | ||
| 68 | QK_TO_MAX = 0x50FF, | ||
| 69 | QK_MOMENTARY = 0x5100, | ||
| 70 | QK_MOMENTARY_MAX = 0x51FF, | ||
| 71 | QK_DEF_LAYER = 0x5200, | ||
| 72 | QK_DEF_LAYER_MAX = 0x52FF, | ||
| 73 | QK_TOGGLE_LAYER = 0x5300, | ||
| 74 | QK_TOGGLE_LAYER_MAX = 0x53FF, | ||
| 75 | QK_ONE_SHOT_LAYER = 0x5400, | ||
| 76 | QK_ONE_SHOT_LAYER_MAX = 0x54FF, | ||
| 77 | QK_ONE_SHOT_MOD = 0x5500, | ||
| 78 | QK_ONE_SHOT_MOD_MAX = 0x55FF, | ||
| 79 | #ifndef DISABLE_CHORDING | ||
| 80 | QK_CHORDING = 0x5600, | ||
| 81 | QK_CHORDING_MAX = 0x56FF, | ||
| 82 | #endif | ||
| 83 | QK_MOD_TAP = 0x6000, | ||
| 84 | QK_MOD_TAP_MAX = 0x6FFF, | ||
| 85 | QK_TAP_DANCE = 0x7100, | ||
| 86 | QK_TAP_DANCE_MAX = 0x71FF, | ||
| 87 | #ifdef UNICODE_ENABLE | ||
| 88 | QK_UNICODE = 0x8000, | ||
| 89 | QK_UNICODE_MAX = 0xFFFF, | ||
| 90 | #endif | ||
| 91 | |||
| 92 | // Loose keycodes - to be used directly | ||
| 93 | |||
| 94 | RESET = 0x7000, | ||
| 95 | DEBUG, | ||
| 96 | MAGIC_SWAP_CONTROL_CAPSLOCK, | ||
| 97 | MAGIC_CAPSLOCK_TO_CONTROL, | ||
| 98 | MAGIC_SWAP_LALT_LGUI, | ||
| 99 | MAGIC_SWAP_RALT_RGUI, | ||
| 100 | MAGIC_NO_GUI, | ||
| 101 | MAGIC_SWAP_GRAVE_ESC, | ||
| 102 | MAGIC_SWAP_BACKSLASH_BACKSPACE, | ||
| 103 | MAGIC_HOST_NKRO, | ||
| 104 | MAGIC_SWAP_ALT_GUI, | ||
| 105 | MAGIC_UNSWAP_CONTROL_CAPSLOCK, | ||
| 106 | MAGIC_UNCAPSLOCK_TO_CONTROL, | ||
| 107 | MAGIC_UNSWAP_LALT_LGUI, | ||
| 108 | MAGIC_UNSWAP_RALT_RGUI, | ||
| 109 | MAGIC_UNNO_GUI, | ||
| 110 | MAGIC_UNSWAP_GRAVE_ESC, | ||
| 111 | MAGIC_UNSWAP_BACKSLASH_BACKSPACE, | ||
| 112 | MAGIC_UNHOST_NKRO, | ||
| 113 | MAGIC_UNSWAP_ALT_GUI, | ||
| 114 | |||
| 115 | // Leader key | ||
| 116 | #ifndef DISABLE_LEADER | ||
| 117 | KC_LEAD, | ||
| 118 | #endif | ||
| 119 | |||
| 120 | // Audio on/off/toggle | ||
| 121 | AU_ON, | ||
| 122 | AU_OFF, | ||
| 123 | AU_TOG, | ||
| 124 | |||
| 125 | // Music mode on/off/toggle | ||
| 126 | MU_ON, | ||
| 127 | MU_OFF, | ||
| 128 | MU_TOG, | ||
| 129 | |||
| 130 | // Music voice iterate | ||
| 131 | MUV_IN, | ||
| 132 | MUV_DE, | ||
| 133 | |||
| 134 | // Midi mode on/off | ||
| 135 | MIDI_ON, | ||
| 136 | MIDI_OFF, | ||
| 137 | |||
| 138 | // Backlight functionality | ||
| 139 | BL_0, | ||
| 140 | BL_1, | ||
| 141 | BL_2, | ||
| 142 | BL_3, | ||
| 143 | BL_4, | ||
| 144 | BL_5, | ||
| 145 | BL_6, | ||
| 146 | BL_7, | ||
| 147 | BL_8, | ||
| 148 | BL_9, | ||
| 149 | BL_10, | ||
| 150 | BL_11, | ||
| 151 | BL_12, | ||
| 152 | BL_13, | ||
| 153 | BL_14, | ||
| 154 | BL_15, | ||
| 155 | BL_DEC, | ||
| 156 | BL_INC, | ||
| 157 | BL_TOGG, | ||
| 158 | BL_STEP, | ||
| 159 | |||
| 160 | // Left shift, open paren | ||
| 161 | KC_LSPO, | ||
| 162 | |||
| 163 | // Right shift, close paren | ||
| 164 | KC_RSPC, | ||
| 165 | |||
| 166 | // always leave at the end | ||
| 167 | SAFE_RANGE | ||
| 168 | }; | ||
| 169 | |||
| 170 | // Ability to use mods in layouts | ||
| 171 | #define LCTL(kc) (kc | QK_LCTL) | ||
| 172 | #define LSFT(kc) (kc | QK_LSFT) | ||
| 173 | #define LALT(kc) (kc | QK_LALT) | ||
| 174 | #define LGUI(kc) (kc | QK_LGUI) | ||
| 175 | #define RCTL(kc) (kc | QK_RCTL) | ||
| 176 | #define RSFT(kc) (kc | QK_RSFT) | ||
| 177 | #define RALT(kc) (kc | QK_RALT) | ||
| 178 | #define RGUI(kc) (kc | QK_RGUI) | ||
| 179 | |||
| 180 | #define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI) | ||
| 181 | #define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT) | ||
| 182 | #define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI) | ||
| 183 | |||
| 184 | #define MOD_HYPR 0xf | ||
| 185 | #define MOD_MEH 0x7 | ||
| 186 | |||
| 187 | |||
| 188 | // Aliases for shifted symbols | ||
| 189 | // Each key has a 4-letter code, and some have longer aliases too. | ||
| 190 | // While the long aliases are descriptive, the 4-letter codes | ||
| 191 | // make for nicer grid layouts (everything lines up), and are | ||
| 192 | // the preferred style for Quantum. | ||
| 193 | #define KC_TILD LSFT(KC_GRV) // ~ | ||
| 194 | #define KC_TILDE KC_TILD | ||
| 195 | |||
| 196 | #define KC_EXLM LSFT(KC_1) // ! | ||
| 197 | #define KC_EXCLAIM KC_EXLM | ||
| 198 | |||
| 199 | #define KC_AT LSFT(KC_2) // @ | ||
| 200 | |||
| 201 | #define KC_HASH LSFT(KC_3) // # | ||
| 202 | |||
| 203 | #define KC_DLR LSFT(KC_4) // $ | ||
| 204 | #define KC_DOLLAR KC_DLR | ||
| 205 | |||
| 206 | #define KC_PERC LSFT(KC_5) // % | ||
| 207 | #define KC_PERCENT KC_PERC | ||
| 208 | |||
| 209 | #define KC_CIRC LSFT(KC_6) // ^ | ||
| 210 | #define KC_CIRCUMFLEX KC_CIRC | ||
| 211 | |||
| 212 | #define KC_AMPR LSFT(KC_7) // & | ||
| 213 | #define KC_AMPERSAND KC_AMPR | ||
| 214 | |||
| 215 | #define KC_ASTR LSFT(KC_8) // * | ||
| 216 | #define KC_ASTERISK KC_ASTR | ||
| 217 | |||
| 218 | #define KC_LPRN LSFT(KC_9) // ( | ||
| 219 | #define KC_LEFT_PAREN KC_LPRN | ||
| 220 | |||
| 221 | #define KC_RPRN LSFT(KC_0) // ) | ||
| 222 | #define KC_RIGHT_PAREN KC_RPRN | ||
| 223 | |||
| 224 | #define KC_UNDS LSFT(KC_MINS) // _ | ||
| 225 | #define KC_UNDERSCORE KC_UNDS | ||
| 226 | |||
| 227 | #define KC_PLUS LSFT(KC_EQL) // + | ||
| 228 | |||
| 229 | #define KC_LCBR LSFT(KC_LBRC) // { | ||
| 230 | #define KC_LEFT_CURLY_BRACE KC_LCBR | ||
| 231 | |||
| 232 | #define KC_RCBR LSFT(KC_RBRC) // } | ||
| 233 | #define KC_RIGHT_CURLY_BRACE KC_RCBR | ||
| 234 | |||
| 235 | #define KC_LABK LSFT(KC_COMM) // < | ||
| 236 | #define KC_LEFT_ANGLE_BRACKET KC_LABK | ||
| 237 | |||
| 238 | #define KC_RABK LSFT(KC_DOT) // > | ||
| 239 | #define KC_RIGHT_ANGLE_BRACKET KC_RABK | ||
| 240 | |||
| 241 | #define KC_COLN LSFT(KC_SCLN) // : | ||
| 242 | #define KC_COLON KC_COLN | ||
| 243 | |||
| 244 | #define KC_PIPE LSFT(KC_BSLS) // | | ||
| 245 | |||
| 246 | #define KC_LT LSFT(KC_COMM) // < | ||
| 247 | |||
| 248 | #define KC_GT LSFT(KC_DOT) // > | ||
| 249 | |||
| 250 | #define KC_QUES LSFT(KC_SLSH) // ? | ||
| 251 | #define KC_QUESTION KC_QUES | ||
| 252 | |||
| 253 | #define KC_DQT LSFT(KC_QUOT) // " | ||
| 254 | #define KC_DOUBLE_QUOTE KC_DQT | ||
| 255 | #define KC_DQUO KC_DQT | ||
| 256 | |||
| 257 | #define KC_DELT KC_DELETE // Del key (four letter code) | ||
| 258 | |||
| 259 | // Alias for function layers than expand past FN31 | ||
| 260 | #define FUNC(kc) (kc | QK_FUNCTION) | ||
| 261 | |||
| 262 | // Aliases | ||
| 263 | #define S(kc) LSFT(kc) | ||
| 264 | #define F(kc) FUNC(kc) | ||
| 265 | |||
| 266 | #define M(kc) (kc | QK_MACRO) | ||
| 267 | |||
| 268 | #define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE) | ||
| 269 | |||
| 270 | // L-ayer, T-ap - 256 keycode max, 16 layer max | ||
| 271 | #define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8)) | ||
| 272 | |||
| 273 | #define AG_SWAP MAGIC_SWAP_ALT_GUI | ||
| 274 | #define AG_NORM MAGIC_UNSWAP_ALT_GUI | ||
| 275 | |||
| 276 | #define BL_ON BL_9 | ||
| 277 | #define BL_OFF BL_0 | ||
| 278 | |||
| 279 | #define MI_ON MIDI_ON | ||
| 280 | #define MI_OFF MIDI_OFF | ||
| 281 | |||
| 282 | // GOTO layer - 16 layers max | ||
| 283 | // when: | ||
| 284 | // ON_PRESS = 1 | ||
| 285 | // ON_RELEASE = 2 | ||
| 286 | // Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default. | ||
| 287 | #define TO(layer, when) (layer | QK_TO | (when << 0x4)) | ||
| 288 | |||
| 289 | // Momentary switch layer - 256 layer max | ||
| 290 | #define MO(layer) (layer | QK_MOMENTARY) | ||
| 291 | |||
| 292 | // Set default layer - 256 layer max | ||
| 293 | #define DF(layer) (layer | QK_DEF_LAYER) | ||
| 294 | |||
| 295 | // Toggle to layer - 256 layer max | ||
| 296 | #define TG(layer) (layer | QK_TOGGLE_LAYER) | ||
| 297 | |||
| 298 | // One-shot layer - 256 layer max | ||
| 299 | #define OSL(layer) (layer | QK_ONE_SHOT_LAYER) | ||
| 300 | |||
| 301 | // One-shot mod | ||
| 302 | #define OSM(layer) (layer | QK_ONE_SHOT_MOD) | ||
| 303 | |||
| 304 | // M-od, T-ap - 256 keycode max | ||
| 305 | #define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8)) | ||
| 306 | #define CTL_T(kc) MT(MOD_LCTL, kc) | ||
| 307 | #define SFT_T(kc) MT(MOD_LSFT, kc) | ||
| 308 | #define ALT_T(kc) MT(MOD_LALT, kc) | ||
| 309 | #define GUI_T(kc) MT(MOD_LGUI, kc) | ||
| 310 | #define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal | ||
| 311 | #define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl | ||
| 312 | #define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui | ||
| 313 | #define ALL_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI), kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/ | ||
| 314 | |||
| 315 | // Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap | ||
| 316 | #define KC_HYPR HYPR(KC_NO) | ||
| 317 | #define KC_MEH MEH(KC_NO) | ||
| 318 | |||
| 319 | #ifdef UNICODE_ENABLE | ||
| 320 | // For sending unicode codes. | ||
| 321 | // You may not send codes over 7FFF -- this supports most of UTF8. | ||
| 322 | // To have a key that sends out Œ, go UC(0x0152) | ||
| 323 | #define UNICODE(n) (n | QK_UNICODE) | ||
| 324 | #define UC(n) UNICODE(n) | ||
| 325 | #endif | ||
| 326 | |||
| 327 | |||
| 328 | #endif | ||
diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c new file mode 100644 index 000000000..76872ac59 --- /dev/null +++ b/quantum/keymap_common.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2012,2013 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "keymap.h" | ||
| 19 | #include "report.h" | ||
| 20 | #include "keycode.h" | ||
| 21 | #include "action_layer.h" | ||
| 22 | #if defined(__AVR__) | ||
| 23 | #include <util/delay.h> | ||
| 24 | #include <stdio.h> | ||
| 25 | #endif | ||
| 26 | #include "action.h" | ||
| 27 | #include "action_macro.h" | ||
| 28 | #include "debug.h" | ||
| 29 | #include "backlight.h" | ||
| 30 | #include "quantum.h" | ||
| 31 | |||
| 32 | #ifdef MIDI_ENABLE | ||
| 33 | #include "keymap_midi.h" | ||
| 34 | #endif | ||
| 35 | |||
| 36 | extern keymap_config_t keymap_config; | ||
| 37 | |||
| 38 | #include <inttypes.h> | ||
| 39 | |||
| 40 | /* converts key to action */ | ||
| 41 | action_t action_for_key(uint8_t layer, keypos_t key) | ||
| 42 | { | ||
| 43 | // 16bit keycodes - important | ||
| 44 | uint16_t keycode = keymap_key_to_keycode(layer, key); | ||
| 45 | |||
| 46 | // keycode remapping | ||
| 47 | keycode = keycode_config(keycode); | ||
| 48 | |||
| 49 | action_t action; | ||
| 50 | uint8_t action_layer, when, mod; | ||
| 51 | // The arm-none-eabi compiler generates out of bounds warnings when using the fn_actions directly for some reason | ||
| 52 | const uint16_t* actions = fn_actions; | ||
| 53 | |||
| 54 | switch (keycode) { | ||
| 55 | case KC_FN0 ... KC_FN31: | ||
| 56 | action.code = pgm_read_word(&actions[FN_INDEX(keycode)]); | ||
| 57 | break; | ||
| 58 | case KC_A ... KC_EXSEL: | ||
| 59 | case KC_LCTRL ... KC_RGUI: | ||
| 60 | action.code = ACTION_KEY(keycode); | ||
| 61 | break; | ||
| 62 | case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE: | ||
| 63 | action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode)); | ||
| 64 | break; | ||
| 65 | case KC_AUDIO_MUTE ... KC_WWW_FAVORITES: | ||
| 66 | action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode)); | ||
| 67 | break; | ||
| 68 | case KC_MS_UP ... KC_MS_ACCEL2: | ||
| 69 | action.code = ACTION_MOUSEKEY(keycode); | ||
| 70 | break; | ||
| 71 | case KC_TRNS: | ||
| 72 | action.code = ACTION_TRANSPARENT; | ||
| 73 | break; | ||
| 74 | case QK_MODS ... QK_MODS_MAX: ; | ||
| 75 | // Has a modifier | ||
| 76 | // Split it up | ||
| 77 | action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key | ||
| 78 | break; | ||
| 79 | case QK_FUNCTION ... QK_FUNCTION_MAX: ; | ||
| 80 | // Is a shortcut for function action_layer, pull last 12bits | ||
| 81 | // This means we have 4,096 FN macros at our disposal | ||
| 82 | action.code = pgm_read_word(&actions[(int)keycode & 0xFFF]); | ||
| 83 | break; | ||
| 84 | case QK_MACRO ... QK_MACRO_MAX: | ||
| 85 | action.code = ACTION_MACRO(keycode & 0xFF); | ||
| 86 | break; | ||
| 87 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: | ||
| 88 | action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); | ||
| 89 | break; | ||
| 90 | case QK_TO ... QK_TO_MAX: ; | ||
| 91 | // Layer set "GOTO" | ||
| 92 | when = (keycode >> 0x4) & 0x3; | ||
| 93 | action_layer = keycode & 0xF; | ||
| 94 | action.code = ACTION_LAYER_SET(action_layer, when); | ||
| 95 | break; | ||
| 96 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: ; | ||
| 97 | // Momentary action_layer | ||
| 98 | action_layer = keycode & 0xFF; | ||
| 99 | action.code = ACTION_LAYER_MOMENTARY(action_layer); | ||
| 100 | break; | ||
| 101 | case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: ; | ||
| 102 | // Set default action_layer | ||
| 103 | action_layer = keycode & 0xFF; | ||
| 104 | action.code = ACTION_DEFAULT_LAYER_SET(action_layer); | ||
| 105 | break; | ||
| 106 | case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: ; | ||
| 107 | // Set toggle | ||
| 108 | action_layer = keycode & 0xFF; | ||
| 109 | action.code = ACTION_LAYER_TOGGLE(action_layer); | ||
| 110 | break; | ||
| 111 | case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: ; | ||
| 112 | // OSL(action_layer) - One-shot action_layer | ||
| 113 | action_layer = keycode & 0xFF; | ||
| 114 | action.code = ACTION_LAYER_ONESHOT(action_layer); | ||
| 115 | break; | ||
| 116 | case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: ; | ||
| 117 | // OSM(mod) - One-shot mod | ||
| 118 | mod = keycode & 0xFF; | ||
| 119 | action.code = ACTION_MODS_ONESHOT(mod); | ||
| 120 | break; | ||
| 121 | case QK_MOD_TAP ... QK_MOD_TAP_MAX: | ||
| 122 | action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); | ||
| 123 | break; | ||
| 124 | #ifdef BACKLIGHT_ENABLE | ||
| 125 | case BL_0 ... BL_15: | ||
| 126 | action.code = ACTION_BACKLIGHT_LEVEL(keycode - BL_0); | ||
| 127 | break; | ||
| 128 | case BL_DEC: | ||
| 129 | action.code = ACTION_BACKLIGHT_DECREASE(); | ||
| 130 | break; | ||
| 131 | case BL_INC: | ||
| 132 | action.code = ACTION_BACKLIGHT_INCREASE(); | ||
| 133 | break; | ||
| 134 | case BL_TOGG: | ||
| 135 | action.code = ACTION_BACKLIGHT_TOGGLE(); | ||
| 136 | break; | ||
| 137 | case BL_STEP: | ||
| 138 | action.code = ACTION_BACKLIGHT_STEP(); | ||
| 139 | break; | ||
| 140 | #endif | ||
| 141 | default: | ||
| 142 | action.code = ACTION_NO; | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | return action; | ||
| 146 | } | ||
| 147 | |||
| 148 | __attribute__ ((weak)) | ||
| 149 | const uint16_t PROGMEM fn_actions[] = { | ||
| 150 | |||
| 151 | }; | ||
| 152 | |||
| 153 | /* Macro */ | ||
| 154 | __attribute__ ((weak)) | ||
| 155 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 156 | { | ||
| 157 | return MACRO_NONE; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* Function */ | ||
| 161 | __attribute__ ((weak)) | ||
| 162 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 163 | { | ||
| 164 | } | ||
| 165 | |||
| 166 | /* translates key to keycode */ | ||
| 167 | uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) | ||
| 168 | { | ||
| 169 | // Read entire word (16bits) | ||
| 170 | return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]); | ||
| 171 | } | ||
diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h new file mode 100644 index 000000000..4c3096054 --- /dev/null +++ b/quantum/keymap_extras/keymap_bepo.h | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | /* Keymap macros for the French BÉPO layout - http://bepo.fr */ | ||
| 2 | #ifndef KEYMAP_BEPO_H | ||
| 3 | #define KEYMAP_BEPO_H | ||
| 4 | |||
| 5 | #include "keymap.h" | ||
| 6 | |||
| 7 | // Alt gr | ||
| 8 | #ifndef ALTGR | ||
| 9 | #define ALTGR(kc) RALT(kc) | ||
| 10 | #endif | ||
| 11 | #ifndef ALGR | ||
| 12 | #define ALGR(kc) ALTGR(kc) | ||
| 13 | #endif | ||
| 14 | #define BP_ALGR KC_RALT | ||
| 15 | |||
| 16 | // Normal characters | ||
| 17 | // First row (on usual keyboards) | ||
| 18 | #define BP_DOLLAR KC_GRAVE // $ | ||
| 19 | #define BP_DLR BP_DOLLAR | ||
| 20 | #define BP_DOUBLE_QUOTE KC_1 // " | ||
| 21 | #define BP_DQOT BP_DOUBLE_QUOTE | ||
| 22 | #define BP_LEFT_GUILLEMET KC_2 // « | ||
| 23 | #define BP_LGIL BP_LEFT_GUILLEMET | ||
| 24 | #define BP_RIGHT_GUILLEMET KC_3 // » | ||
| 25 | #define BP_RGIL BP_RIGHT_GUILLEMET | ||
| 26 | #define BP_LEFT_PAREN KC_4 // ( | ||
| 27 | #define BP_LPRN BP_LEFT_PAREN | ||
| 28 | #define BP_RIGHT_PAREN KC_5 // ) | ||
| 29 | #define BP_RPRN BP_RIGHT_PAREN | ||
| 30 | #define BP_AT KC_6 // @ | ||
| 31 | #define BP_PLUS KC_7 // + | ||
| 32 | #define BP_MINUS KC_8 // - | ||
| 33 | #define BP_MINS BP_MINUS | ||
| 34 | #define BP_SLASH KC_9 // / | ||
| 35 | #define BP_SLSH BP_SLASH | ||
| 36 | #define BP_ASTERISK KC_0 // * | ||
| 37 | #define BP_ASTR BP_ASTERISK | ||
| 38 | #define BP_EQUAL KC_MINUS // = | ||
| 39 | #define BP_EQL BP_EQUAL | ||
| 40 | #define BP_PERCENT KC_EQUAL // % | ||
| 41 | #define BP_PERC BP_PERCENT | ||
| 42 | |||
| 43 | // Second row | ||
| 44 | #define BP_B KC_Q | ||
| 45 | #define BP_E_ACUTE KC_W // é | ||
| 46 | #define BP_ECUT BP_E_ACUTE | ||
| 47 | #define BP_P KC_E | ||
| 48 | #define BP_O KC_R | ||
| 49 | #define BP_E_GRAVE KC_T // è | ||
| 50 | #define BP_EGRV BP_E_GRAVE | ||
| 51 | #define BP_DEAD_CIRCUMFLEX KC_Y // dead ^ | ||
| 52 | #define BP_DCRC BP_DEAD_CIRCUMFLEX | ||
| 53 | #define BP_V KC_U | ||
| 54 | #define BP_D KC_I | ||
| 55 | #define BP_L KC_O | ||
| 56 | #define BP_J KC_P | ||
| 57 | #define BP_Z KC_LBRACKET | ||
| 58 | #define BP_W KC_RBRACKET | ||
| 59 | |||
| 60 | // Third row | ||
| 61 | #define BP_A KC_A | ||
| 62 | #define BP_U KC_S | ||
| 63 | #define BP_I KC_D | ||
| 64 | #define BP_E KC_F | ||
| 65 | #define BP_COMMA KC_G // , | ||
| 66 | #define BP_COMM BP_COMMA | ||
| 67 | #define BP_C KC_H | ||
| 68 | #define BP_T KC_J | ||
| 69 | #define BP_S KC_K | ||
| 70 | #define BP_R KC_L | ||
| 71 | #define BP_N KC_SCOLON | ||
| 72 | #define BP_M KC_QUOTE | ||
| 73 | #define BP_C_CEDILLA KC_BSLASH // ç | ||
| 74 | #define BP_CCED BP_C_CEDILLA | ||
| 75 | |||
| 76 | // Fourth row | ||
| 77 | #define BP_E_CIRCUMFLEX KC_NONUS_BSLASH // ê | ||
| 78 | #define BP_ECRC BP_E_CIRCUMFLEX | ||
| 79 | #define BP_A_GRAVE KC_Z // à | ||
| 80 | #define BP_AGRV BP_A_GRAVE | ||
| 81 | #define BP_Y KC_X | ||
| 82 | #define BP_X KC_C | ||
| 83 | #define BP_DOT KC_V // . | ||
| 84 | #define BP_K KC_B | ||
| 85 | #define BP_APOSTROPHE KC_N | ||
| 86 | #define BP_APOS BP_APOSTROPHE // ' | ||
| 87 | #define BP_Q KC_M | ||
| 88 | #define BP_G KC_COMMA | ||
| 89 | #define BP_H KC_DOT | ||
| 90 | #define BP_F KC_SLASH | ||
| 91 | |||
| 92 | // Shifted characters | ||
| 93 | // First row | ||
| 94 | #define BP_HASH LSFT(BP_DOLLAR) // # | ||
| 95 | #define BP_1 LSFT(KC_1) | ||
| 96 | #define BP_2 LSFT(KC_2) | ||
| 97 | #define BP_3 LSFT(KC_3) | ||
| 98 | #define BP_4 LSFT(KC_4) | ||
| 99 | #define BP_5 LSFT(KC_5) | ||
| 100 | #define BP_6 LSFT(KC_6) | ||
| 101 | #define BP_7 LSFT(KC_7) | ||
| 102 | #define BP_8 LSFT(KC_8) | ||
| 103 | #define BP_9 LSFT(KC_9) | ||
| 104 | #define BP_0 LSFT(KC_0) | ||
| 105 | #define BP_DEGREE LSFT(BP_EQUAL) // ° | ||
| 106 | #define BP_DEGR BP_DEGREE | ||
| 107 | #define BP_GRAVE LSFT(BP_PERCENT) // ` | ||
| 108 | #define BP_GRV BP_GRAVE | ||
| 109 | |||
| 110 | // Second row | ||
| 111 | #define BP_EXCLAIM LSFT(BP_DEAD_CIRCUMFLEX) // ! | ||
| 112 | #define BP_EXLM BP_EXCLAIM | ||
| 113 | |||
| 114 | // Third row | ||
| 115 | #define BP_SCOLON LSFT(BP_COMMA) // ; | ||
| 116 | #define BP_SCLN BP_SCOLON | ||
| 117 | |||
| 118 | // Fourth row | ||
| 119 | #define BP_COLON LSFT(BP_DOT) // : | ||
| 120 | #define BP_COLN BP_COLON | ||
| 121 | #define BP_QUESTION LSFT(BP_QUOTE) // ? | ||
| 122 | #define BP_QEST BP_QUESTION | ||
| 123 | |||
| 124 | // Space bar | ||
| 125 | #define BP_NON_BREAKING_SPACE LSFT(KC_SPACE) | ||
| 126 | #define BP_NBSP BP_NON_BREAKING_SPACE | ||
| 127 | |||
| 128 | // AltGr-ed characters | ||
| 129 | // First row | ||
| 130 | #define BP_EN_DASH ALTGR(BP_DOLLAR) // – | ||
| 131 | #define BP_NDSH BP_EN_DASH | ||
| 132 | #define BP_EM_DASH ALTGR(KC_1) // — | ||
| 133 | #define BP_MDSH BP_EM_DASH | ||
| 134 | #define BP_LESS ALTGR(KC_2) // < | ||
| 135 | #define BP_GREATER ALTGR(KC_3) // > | ||
| 136 | #define BP_GRTR BP_GREATER | ||
| 137 | #define BP_LBRACKET ALTGR(KC_4) // [ | ||
| 138 | #define BP_LBRC BP_LBRACKET | ||
| 139 | #define BP_RBRACKET ALTGR(KC_5) // ] | ||
| 140 | #define BP_RBRC BP_RBRACKET | ||
| 141 | #define BP_CIRCUMFLEX ALTGR(KC_6) // ^ | ||
| 142 | #define BP_CIRC BP_CIRCUMFLEX | ||
| 143 | #define BP_PLUS_MINUS ALTGR(KC_7) // ± | ||
| 144 | #define BP_PSMS BP_PLUS_MINUS | ||
| 145 | #define BP_MATH_MINUS ALTGR(KC_8) // − | ||
| 146 | #define BP_MMNS BP_MATH_MINUS | ||
| 147 | #define BP_OBELUS ALTGR(KC_9) // ÷ | ||
| 148 | #define BP_OBEL BP_OBELUS | ||
| 149 | // more conventional name of the symbol | ||
| 150 | #define BP_DIVISION_SIGN BP_OBELUS | ||
| 151 | #define BP_DVSN BP_DIVISION_SIGN | ||
| 152 | #define BP_TIMES ALTGR(KC_0) // × | ||
| 153 | #define BP_TIMS BP_TIMES | ||
| 154 | #define BP_DIFFERENT ALTGR(BP_EQUAL) // ≠ | ||
| 155 | #define BP_DIFF BP_DIFFERENT | ||
| 156 | #define BP_PERMILLE ALTGR(BP_PERCENT) // ‰ | ||
| 157 | #define BP_PMIL BP_PERMILLE | ||
| 158 | |||
| 159 | // Second row | ||
| 160 | #define BP_PIPE ALTGR(BP_B) // | | ||
| 161 | #define BP_DEAD_ACUTE ALTGR(BP_E_ACUTE) // dead ´ | ||
| 162 | #define BP_DACT BP_DEAD_ACUTE | ||
| 163 | #define BP_AMPERSAND ALTGR(BP_P) // & | ||
| 164 | #define BP_AMPR BP_AMPERSAND | ||
| 165 | #define BP_OE_LIGATURE ALTGR(BP_O) // œ | ||
| 166 | #define BP_OE BP_OE_LIGATURE | ||
| 167 | #define BP_DEAD_GRAVE ALTGR(BP_E_GRAVE) // ` | ||
| 168 | #define BP_DGRV BP_DEAD_GRAVE | ||
| 169 | #define BP_INVERTED_EXCLAIM ALTGR(BP_DEAD_CIRCUMFLEX) // ¡ | ||
| 170 | #define BP_IXLM BP_INVERTED_EXCLAIM | ||
| 171 | #define BP_DEAD_CARON ALTGR(BP_V) // dead ˇ | ||
| 172 | #define BP_DCAR BP_DEAD_CARON | ||
| 173 | #define BP_ETH ALTGR(BP_D) // ð | ||
| 174 | #define BP_DEAD_SLASH ALTGR(BP_L) // dead / | ||
| 175 | #define BP_DSLH BP_DEAD_SLASH | ||
| 176 | #define BP_IJ_LIGATURE ALTGR(BP_J) // ij | ||
| 177 | #define BP_IJ BP_IJ_LIGATURE | ||
| 178 | #define BP_SCHWA ALTGR(BP_Z) // ə | ||
| 179 | #define BP_SCWA BP_SCHWA | ||
| 180 | #define BP_DEAD_BREVE ALTGR(BP_W) // dead ˘ | ||
| 181 | #define BP_DBRV BP_DEAD_BREVE | ||
| 182 | |||
| 183 | // Third row | ||
| 184 | #define BP_AE_LIGATURE ALTGR(BP_A) // æ | ||
| 185 | #define BP_AE BP_AE_LIGATURE | ||
| 186 | #define BP_U_GRAVE AGR(BP_U) // ù | ||
| 187 | #define BP_UGRV BP_U_GRAVE | ||
| 188 | #define BP_DEAD_TREMA ALTGR(BP_I) // dead ¨ (trema/umlaut/diaresis) | ||
| 189 | #define BP_DTRM BP_DEAD_TREMA | ||
| 190 | #define BP_EURO ALTGR(BP_E) // € | ||
| 191 | #define BP_TYPOGRAPHICAL_APOSTROPHE ALTGR(BP_COMMMA) // ’ | ||
| 192 | #define BP_TAPO BP_TYPOGRAPHICAL_APOSTROPHE | ||
| 193 | #define BP_COPYRIGHT ALTGR(BP_C) // © | ||
| 194 | #define BP_CPRT BP_COPYRIGHT | ||
| 195 | #define BP_THORN ALTGR(BP_T) // þ | ||
| 196 | #define BP_THRN BP_THORN | ||
| 197 | #define BP_SHARP_S ALTGR(BP_S) // ß | ||
| 198 | #define BP_SRPS BP_SHARP_S | ||
| 199 | #define BP_REGISTERED_TRADEMARK ALTGR(BP_R) // ® | ||
| 200 | #define BP_RTM BP_REGISTERED_TRADEMARK | ||
| 201 | #define BP_DEAD_TILDE ALTGR(BP_N) // dead ~ | ||
| 202 | #define BP_DTLD BP_DEAD_TILDE | ||
| 203 | #define BP_DEAD_MACRON ALTGR(BP_M) // dead ¯ | ||
| 204 | #define BP_DMCR BP_DEAD_MACRON | ||
| 205 | #define BP_DEAD_CEDILLA ALTGR(BP_C_CEDILLA) // dead ¸ | ||
| 206 | #define BP_DCED BP_DEAD_CEDILLA | ||
| 207 | |||
| 208 | // Fourth row | ||
| 209 | #define BP_NONUS_SLASH ALTGR(BP_E_CIRCUMFLEX) // / on non-us backslash key (102nd key, ê in bépo) | ||
| 210 | #define BP_NUSL BP_NONUS_SLASH | ||
| 211 | #define BP_BACKSLASH ALTGR(BP_A_GRAVE) /* \ */ | ||
| 212 | #define BP_BSLS BP_BACKSLASH | ||
| 213 | #define BP_LEFT_CURLY_BRACE ALTGR(BP_Y) // { | ||
| 214 | #define BP_LCBR BP_LEFT_CURLY_BRACE | ||
| 215 | #define BP_RIGHT_CURLY_BRACE ALTGR(BP_X) // } | ||
| 216 | #define BP_RCBR BP_RIGHT_CURLY_BRACE | ||
| 217 | #define BP_ELLIPSIS ALTGR(BP_DOT) // … | ||
| 218 | #define BP_ELPS BP_ELLIPSIS | ||
| 219 | #define BP_TILDE ALTGR(BP_K) // ~ | ||
| 220 | #define BP_TILD BP_TILDE | ||
| 221 | #define BP_INVERTED_QUESTION ALTGR(BP_QUESTION) // ¿ | ||
| 222 | #define BP_IQST BP_INVERTED_QUESTION | ||
| 223 | #define BP_DEAD_RING ALTGR(BP_Q) // dead ° | ||
| 224 | #define BP_DRNG BP_DEAD_RING | ||
| 225 | #define BP_DEAD_GREEK ALTGR(BP_G) // dead Greek key (following key will make a Greek letter) | ||
| 226 | #define BP_DGRK BP_DEAD_GREEK | ||
| 227 | #define BP_DAGGER ALTGR(BP_H) // † | ||
| 228 | #define BP_DAGR BP_DAGGER | ||
| 229 | #define BP_DEAD_OGONEK ALTGR(BP_F) // dead ˛ | ||
| 230 | #define BP_DOGO BP_DEAD_OGONEK | ||
| 231 | |||
| 232 | // Space bar | ||
| 233 | #define BP_UNDERSCORE ALTGR(KC_SPACE) // _ | ||
| 234 | #define BP_UNDS BP_UNDERSCORE | ||
| 235 | |||
| 236 | // AltGr-Shifted characters (different from capitalised AltGr-ed characters) | ||
| 237 | // First row | ||
| 238 | #define BP_PARAGRAPH ALTGR(BP_HASH) // ¶ | ||
| 239 | #define BP_PARG BP_PARAGRAPH | ||
| 240 | #define BP_LOW_DOUBLE_QUOTE ALTGR(BP_1) // „ | ||
| 241 | #define BP_LWQT BP_LOW_DOUBLE_QUOTE | ||
| 242 | #define BP_LEFT_DOUBLE_QUOTE ALTGR(BP_2) // “ | ||
| 243 | #define BP_LDQT BP_LEFT_DOUBLE_QUOTE | ||
| 244 | #define BP_RIGHT_DOUBLE_QUOTE ALTGR(BP_3) // ” | ||
| 245 | #define BP_RDQT BP_RIGHT_DOUBLE_QUOTE | ||
| 246 | #define BP_LESS_OR_EQUAL ALTGR(BP_4) // ≤ | ||
| 247 | #define BP_LEQL BP_LESS_OR_EQUAL | ||
| 248 | #define BP_GREATER_OR_EQUAL ALTGR(BP_5) // ≥ | ||
| 249 | #define BP_GEQL BP_GREATER_OR_EQUAL | ||
| 250 | // nothing on ALTGR(BP_6) | ||
| 251 | #define BP_NEGATION ALTGR(BP_7) // ¬ | ||
| 252 | #define BP_NEGT BP_NEGATION | ||
| 253 | #define BP_ONE_QUARTER ALTGR(BP_8) // ¼ | ||
| 254 | #define BP_1QRT BP_ONE_QUARTER | ||
| 255 | #define BP_ONE_HALF ALTGR(BP_9) // ½ | ||
| 256 | #define BP_1HLF BP_ONE_HALF | ||
| 257 | #define BP_THREE_QUARTERS ALTGR(BP_0) // ¾ | ||
| 258 | #define BP_3QRT BP_THREE_QUARTERS | ||
| 259 | #define BP_MINUTES ALTGR(BP_DEGREE) // ′ | ||
| 260 | #define BP_MNUT BP_MINUTES | ||
| 261 | #define BP_SECONDS ALTGR(BP_GRAVE) // ″ | ||
| 262 | #define BP_SCND BP_SECONDS | ||
| 263 | |||
| 264 | // Second row | ||
| 265 | #define BP_BROKEN_PIPE LSFT(BP_PIPE) // ¦ | ||
| 266 | #define BP_BPIP BP_BROKEN_PIPE | ||
| 267 | #define BP_DEAD_DOUBLE_ACUTE LSFT(BP_DEAD_ACUTE) // ˝ | ||
| 268 | #define BP_DDCT BP_DEAD_DOUBLE_ACUTE | ||
| 269 | #define BP_SECTION ALTGR(LSFT(BP_P)) // § | ||
| 270 | #define BP_SECT BP_SECTION | ||
| 271 | // LSFT(BP_DEAD_GRAVE) is actually the same character as LSFT(BP_PERCENT) | ||
| 272 | #define BP_GRAVE_BIS LSFT(BP_DEAD_GRAVE) // ` | ||
| 273 | #define BP_GRVB BP_GRAVE_BIS | ||
| 274 | |||
| 275 | // Third row | ||
| 276 | #define BP_DEAD_DOT_ABOVE LSFT(BP_DEAD_TREMA) // dead ˙ | ||
| 277 | #define BP_DDTA BP_DEAD_DOT_ABOVE | ||
| 278 | #define BP_DEAD_CURRENCY LSFT(BP_EURO) // dead ¤ (next key will generate a currency code like ¥ or £) | ||
| 279 | #define BP_DCUR BP_DEAD_CURRENCY | ||
| 280 | #define BP_DEAD_HORN LSFT(ALTGR(BP_COMMA)) // dead ̛ | ||
| 281 | #define BP_DHRN BP_DEAD_HORN | ||
| 282 | #define BP_LONG_S LSFT(ALTGR(BP_C)) // ſ | ||
| 283 | #define BP_LNGS BP_LONG_S | ||
| 284 | #define BP_TRADEMARK LSFT(BP_REGISTERED_TRADEMARK) // ™ | ||
| 285 | #define BP_TM BP_TRADEMARK | ||
| 286 | #define BP_ORDINAL_INDICATOR_O LSFT(ALTGR(BP_M)) // º | ||
| 287 | #define BP_ORDO BP_ORDINAL_INDICATOR_O | ||
| 288 | #define BP_DEAD_COMMA LSFT(BP_DEAD_CEDILLA) // dead ˛ | ||
| 289 | #define BP_DCOM BP_DEAD_COMMA | ||
| 290 | |||
| 291 | // Fourth row | ||
| 292 | #define BP_LEFT_QUOTE LSFT(ALTGR(BP_Y)) // ‘ | ||
| 293 | #define BP_LQOT BP_LEFT_QUOTE | ||
| 294 | #define BP_RIGHT_QUOTE LSFT(ALTGR(BP_X)) // ’ | ||
| 295 | #define BP_RQOT BP_RIGHT_QUOTE | ||
| 296 | #define BP_INTERPUNCT LSFT(ALTGR(BP_DOT)) // · | ||
| 297 | #define BP_IPCT BP_INTERPUNCT | ||
| 298 | #define BP_DEAD_HOOK_ABOVE LSFT(ALTGR(BP_QUESTION)) // dead ̉ | ||
| 299 | #define BP_DHKA BP_DEAD_HOOK_ABOVE | ||
| 300 | #define BP_DEAD_UNDERDOT LSFT(BP_DEAD_RING) // dead ̣ | ||
| 301 | #define BP_DUDT BP_DEAD_UNDERDOT | ||
| 302 | #define BP_DOUBLE_DAGGER LSFT(BP_DAGGER) // ‡ | ||
| 303 | #define BP_DDGR BP_DOUBLE_DAGGER | ||
| 304 | #define BP_ORDINAL_INDICATOR_A LSFT(ALTGR(BP_F)) // ª | ||
| 305 | #define BP_ORDA BP_ORDINAL_INDICATOR_A | ||
| 306 | |||
| 307 | // Space bar | ||
| 308 | #define BP_NARROW_NON_BREAKING_SPACE ALTGR(BP_NON_BREAKING_SPACE) | ||
| 309 | #define BP_NNBS BP_NARROW_NON_BREAKING_SPACE | ||
| 310 | |||
| 311 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_colemak.h b/quantum/keymap_extras/keymap_colemak.h new file mode 100644 index 000000000..b8d615748 --- /dev/null +++ b/quantum/keymap_extras/keymap_colemak.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | #ifndef KEYMAP_COLEMAK_H | ||
| 2 | #define KEYMAP_COLEMAK_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | // For software implementation of colemak | ||
| 6 | #define CM_Q KC_Q | ||
| 7 | #define CM_W KC_W | ||
| 8 | #define CM_F KC_E | ||
| 9 | #define CM_P KC_R | ||
| 10 | #define CM_G KC_T | ||
| 11 | #define CM_J KC_Y | ||
| 12 | #define CM_L KC_U | ||
| 13 | #define CM_U KC_I | ||
| 14 | #define CM_Y KC_O | ||
| 15 | #define CM_SCLN KC_P | ||
| 16 | |||
| 17 | #define CM_A KC_A | ||
| 18 | #define CM_R KC_S | ||
| 19 | #define CM_S KC_D | ||
| 20 | #define CM_T KC_F | ||
| 21 | #define CM_D KC_G | ||
| 22 | #define CM_H KC_H | ||
| 23 | #define CM_N KC_J | ||
| 24 | #define CM_E KC_K | ||
| 25 | #define CM_I KC_L | ||
| 26 | #define CM_O KC_SCLN | ||
| 27 | #define CM_COLN LSFT(CM_SCLN) | ||
| 28 | |||
| 29 | #define CM_Z KC_Z | ||
| 30 | #define CM_X KC_X | ||
| 31 | #define CM_C KC_C | ||
| 32 | #define CM_V KC_V | ||
| 33 | #define CM_B KC_B | ||
| 34 | #define CM_K KC_N | ||
| 35 | #define CM_M KC_M | ||
| 36 | #define CM_COMM KC_COMM | ||
| 37 | #define CM_DOT KC_DOT | ||
| 38 | #define CM_SLSH KC_SLSH | ||
| 39 | |||
| 40 | // Make it easy to support these in macros | ||
| 41 | // TODO: change macro implementation so these aren't needed | ||
| 42 | #define KC_CM_Q CM_Q | ||
| 43 | #define KC_CM_W CM_W | ||
| 44 | #define KC_CM_F CM_F | ||
| 45 | #define KC_CM_P CM_P | ||
| 46 | #define KC_CM_G CM_G | ||
| 47 | #define KC_CM_J CM_J | ||
| 48 | #define KC_CM_L CM_L | ||
| 49 | #define KC_CM_U CM_U | ||
| 50 | #define KC_CM_Y CM_Y | ||
| 51 | #define KC_CM_SCLN CM_SCLN | ||
| 52 | |||
| 53 | #define KC_CM_A CM_A | ||
| 54 | #define KC_CM_R CM_R | ||
| 55 | #define KC_CM_S CM_S | ||
| 56 | #define KC_CM_T CM_T | ||
| 57 | #define KC_CM_D CM_D | ||
| 58 | #define KC_CM_H CM_H | ||
| 59 | #define KC_CM_N CM_N | ||
| 60 | #define KC_CM_E CM_E | ||
| 61 | #define KC_CM_I CM_I | ||
| 62 | #define KC_CM_O CM_O | ||
| 63 | |||
| 64 | #define KC_CM_Z CM_Z | ||
| 65 | #define KC_CM_X CM_X | ||
| 66 | #define KC_CM_C CM_C | ||
| 67 | #define KC_CM_V CM_V | ||
| 68 | #define KC_CM_B CM_B | ||
| 69 | #define KC_CM_K CM_K | ||
| 70 | #define KC_CM_M CM_M | ||
| 71 | #define KC_CM_COMM CM_COMM | ||
| 72 | #define KC_CM_DOT CM_DOT | ||
| 73 | #define KC_CM_SLSH CM_SLSH | ||
| 74 | |||
| 75 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_dvorak.h b/quantum/keymap_extras/keymap_dvorak.h new file mode 100644 index 000000000..e855056e8 --- /dev/null +++ b/quantum/keymap_extras/keymap_dvorak.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #ifndef KEYMAP_DVORAK_H | ||
| 2 | #define KEYMAP_DVORAK_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Normal characters | ||
| 7 | #define DV_GRV KC_GRV | ||
| 8 | #define DV_1 KC_1 | ||
| 9 | #define DV_2 KC_2 | ||
| 10 | #define DV_3 KC_3 | ||
| 11 | #define DV_4 KC_4 | ||
| 12 | #define DV_5 KC_5 | ||
| 13 | #define DV_6 KC_6 | ||
| 14 | #define DV_7 KC_7 | ||
| 15 | #define DV_8 KC_8 | ||
| 16 | #define DV_9 KC_9 | ||
| 17 | #define DV_0 KC_0 | ||
| 18 | #define DV_LBRC KC_MINS | ||
| 19 | #define DV_RBRC KC_EQL | ||
| 20 | |||
| 21 | #define DV_QUOT KC_Q | ||
| 22 | #define DV_COMM KC_W | ||
| 23 | #define DV_DOT KC_E | ||
| 24 | #define DV_P KC_R | ||
| 25 | #define DV_Y KC_T | ||
| 26 | #define DV_F KC_Y | ||
| 27 | #define DV_G KC_U | ||
| 28 | #define DV_C KC_I | ||
| 29 | #define DV_R KC_O | ||
| 30 | #define DV_L KC_P | ||
| 31 | #define DV_SLSH KC_LBRC | ||
| 32 | #define DV_EQL KC_RBRC | ||
| 33 | |||
| 34 | #define DV_A KC_A | ||
| 35 | #define DV_O KC_S | ||
| 36 | #define DV_E KC_D | ||
| 37 | #define DV_U KC_F | ||
| 38 | #define DV_I KC_G | ||
| 39 | #define DV_D KC_H | ||
| 40 | #define DV_H KC_J | ||
| 41 | #define DV_T KC_K | ||
| 42 | #define DV_N KC_L | ||
| 43 | #define DV_S KC_SCLN | ||
| 44 | #define DV_MINS KC_QUOT | ||
| 45 | |||
| 46 | #define DV_SCLN KC_Z | ||
| 47 | #define DV_Q KC_X | ||
| 48 | #define DV_J KC_C | ||
| 49 | #define DV_K KC_V | ||
| 50 | #define DV_X KC_B | ||
| 51 | #define DV_B KC_N | ||
| 52 | #define DV_M KC_M | ||
| 53 | #define DV_W KC_COMM | ||
| 54 | #define DV_V KC_DOT | ||
| 55 | #define DV_Z KC_SLSH | ||
| 56 | |||
| 57 | // Shifted characters | ||
| 58 | #define DV_TILD LSFT(DV_GRV) | ||
| 59 | #define DV_EXLM LSFT(DV_1) | ||
| 60 | #define DV_AT LSFT(DV_2) | ||
| 61 | #define DV_HASH LSFT(DV_3) | ||
| 62 | #define DV_DLR LSFT(DV_4) | ||
| 63 | #define DV_PERC LSFT(DV_5) | ||
| 64 | #define DV_CIRC LSFT(DV_6) | ||
| 65 | #define DV_AMPR LSFT(DV_7) | ||
| 66 | #define DV_ASTR LSFT(DV_8) | ||
| 67 | #define DV_LPRN LSFT(DV_9) | ||
| 68 | #define DV_RPRN LSFT(DV_0) | ||
| 69 | #define DV_LCBR LSFT(DV_LBRC) | ||
| 70 | #define DV_RCBR LSFT(DV_RBRC) | ||
| 71 | #define DV_UNDS LSFT(DV_MINS) | ||
| 72 | #define DV_PLUS LSFT(DV_EQL) | ||
| 73 | |||
| 74 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_fr_ch.h b/quantum/keymap_extras/keymap_fr_ch.h new file mode 100644 index 000000000..3fd971357 --- /dev/null +++ b/quantum/keymap_extras/keymap_fr_ch.h | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #ifndef KEYMAP_FR_CH | ||
| 2 | #define KEYMAP_FR_CH | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define FR_CH_ALGR KC_RALT | ||
| 9 | |||
| 10 | // normal characters | ||
| 11 | #define FR_CH_Z KC_Y | ||
| 12 | #define FR_CH_Y KC_Z | ||
| 13 | |||
| 14 | #define FR_CH_A KC_A | ||
| 15 | #define FR_CH_B KC_B | ||
| 16 | #define FR_CH_C KC_C | ||
| 17 | #define FR_CH_D KC_D | ||
| 18 | #define FR_CH_E KC_E | ||
| 19 | #define FR_CH_F KC_F | ||
| 20 | #define FR_CH_G KC_G | ||
| 21 | #define FR_CH_H KC_H | ||
| 22 | #define FR_CH_I KC_I | ||
| 23 | #define FR_CH_J KC_J | ||
| 24 | #define FR_CH_K KC_K | ||
| 25 | #define FR_CH_L KC_L | ||
| 26 | #define FR_CH_M KC_M | ||
| 27 | #define FR_CH_N KC_N | ||
| 28 | #define FR_CH_O KC_O | ||
| 29 | #define FR_CH_P KC_P | ||
| 30 | #define FR_CH_Q KC_Q | ||
| 31 | #define FR_CH_R KC_R | ||
| 32 | #define FR_CH_S KC_S | ||
| 33 | #define FR_CH_T KC_T | ||
| 34 | #define FR_CH_U KC_U | ||
| 35 | #define FR_CH_V KC_V | ||
| 36 | #define FR_CH_W KC_W | ||
| 37 | #define FR_CH_X KC_X | ||
| 38 | |||
| 39 | #define FR_CH_0 KC_0 | ||
| 40 | #define FR_CH_1 KC_1 | ||
| 41 | #define FR_CH_2 KC_2 | ||
| 42 | #define FR_CH_3 KC_3 | ||
| 43 | #define FR_CH_4 KC_4 | ||
| 44 | #define FR_CH_5 KC_5 | ||
| 45 | #define FR_CH_6 KC_6 | ||
| 46 | #define FR_CH_7 KC_7 | ||
| 47 | #define FR_CH_8 KC_8 | ||
| 48 | #define FR_CH_9 KC_9 | ||
| 49 | |||
| 50 | #define FR_CH_DOT KC_DOT | ||
| 51 | #define FR_CH_COMM KC_COMM | ||
| 52 | |||
| 53 | #define FR_CH_QUOT KC_MINS | ||
| 54 | #define FR_CH_AE KC_QUOT | ||
| 55 | #define FR_CH_UE KC_LBRC | ||
| 56 | #define FR_CH_OE KC_SCLN | ||
| 57 | |||
| 58 | #define FR_CH_CIRC KC_EQL // accent circumflex ^ and grave ` and ~ | ||
| 59 | #define FR_CH_LESS KC_NUBS // < and > and backslash | ||
| 60 | #define FR_CH_MINS KC_SLSH // - and _ | ||
| 61 | #define FR_CH_DLR KC_BSLS // $, £ and } | ||
| 62 | #define FR_CH_PARA KC_GRV // § and ring ° | ||
| 63 | #define FR_CH_DIAE KC_RBRC // accent ¨ | ||
| 64 | |||
| 65 | // shifted characters | ||
| 66 | #define FR_CH_RING LSFT(KC_GRV) // ° | ||
| 67 | #define FR_CH_EXLM LSFT(KC_RBRC) // ! | ||
| 68 | #define FR_CH_PLUS LSFT(KC_1) // + | ||
| 69 | #define FR_CH_DQOT LSFT(KC_2) // " | ||
| 70 | #define FR_CH_ASTR LSFT(KC_3) // * | ||
| 71 | #define FR_CH_PERC LSFT(KC_5) // % | ||
| 72 | #define FR_CH_AMPR LSFT(KC_6) // & | ||
| 73 | #define FR_CH_SLSH LSFT(KC_7) // / | ||
| 74 | #define FR_CH_LPRN LSFT(KC_8) // ( | ||
| 75 | #define FR_CH_RPRN LSFT(KC_9) // ) | ||
| 76 | #define FR_CH_EQL LSFT(KC_0) // = | ||
| 77 | #define FR_CH_QST LSFT(FR_CH_QUOT) // ? | ||
| 78 | #define FR_CH_MORE LSFT(FR_CH_LESS) // > | ||
| 79 | #define FR_CH_COLN LSFT(KC_DOT) // : | ||
| 80 | #define FR_CH_SCLN LSFT(KC_COMM) // ; | ||
| 81 | #define FR_CH_UNDS LSFT(FR_CH_MINS) // _ | ||
| 82 | #define FR_CH_CCED LSFT(KC_4) // ç | ||
| 83 | #define FR_CH_GRV LSFT(FR_CH_CIRC) // accent grave ` | ||
| 84 | |||
| 85 | // Alt Gr-ed characters | ||
| 86 | #define FR_CH_LCBR ALGR(KC_QUOT) // { | ||
| 87 | #define FR_CH_LBRC ALGR(KC_LBRC) // [ | ||
| 88 | #define FR_CH_RBRC ALGR(KC_9) // ] | ||
| 89 | #define FR_CH_RCBR ALGR(KC_0) // } | ||
| 90 | #define FR_CH_BSLS ALGR(FR_CH_LESS) // backslash | ||
| 91 | #define FR_CH_AT ALGR(KC_2) // @ | ||
| 92 | #define FR_CH_EURO ALGR(KC_E) // € | ||
| 93 | #define FR_CH_TILD ALGR(FR_CH_CIRC) // ~ | ||
| 94 | #define FR_CH_PIPE ALGR(KC_1) // | | ||
| 95 | #define FR_CH_HASH ALGR(KC_3) // # | ||
| 96 | #define FR_CH_ACUT ALGR(FR_CH_QUOT) // accent acute ´ | ||
| 97 | |||
| 98 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_french.h b/quantum/keymap_extras/keymap_french.h new file mode 100644 index 000000000..2a44c80b1 --- /dev/null +++ b/quantum/keymap_extras/keymap_french.h | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #ifndef KEYMAP_FRENCH_H | ||
| 2 | #define KEYMAP_FRENCH_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define NO_ALGR KC_RALT | ||
| 9 | |||
| 10 | // Normal characters | ||
| 11 | #define FR_SUP2 KC_GRV | ||
| 12 | #define FR_AMP KC_1 | ||
| 13 | #define FR_EACU KC_2 | ||
| 14 | #define FR_QUOT KC_3 | ||
| 15 | #define FR_APOS KC_4 | ||
| 16 | #define FR_LPRN KC_5 | ||
| 17 | #define FR_MINS KC_6 | ||
| 18 | #define FR_EGRV KC_7 | ||
| 19 | #define FR_UNDS KC_8 | ||
| 20 | #define FR_CCED KC_9 | ||
| 21 | #define FR_AGRV KC_0 | ||
| 22 | #define FR_RPRN KC_MINS | ||
| 23 | #define FR_EQL KC_EQL | ||
| 24 | |||
| 25 | #define FR_A KC_Q | ||
| 26 | #define FR_Z KC_W | ||
| 27 | #define FR_CIRC KC_LBRC | ||
| 28 | #define FR_DLR KC_RBRC | ||
| 29 | |||
| 30 | #define FR_Q KC_A | ||
| 31 | #define FR_M KC_SCLN | ||
| 32 | #define FR_UGRV KC_QUOT | ||
| 33 | #define FR_ASTR KC_NUHS | ||
| 34 | |||
| 35 | #define FR_LESS KC_NUBS | ||
| 36 | #define FR_W KC_Z | ||
| 37 | #define FR_COMM KC_M | ||
| 38 | #define FR_SCLN KC_COMM | ||
| 39 | #define FR_COLN KC_DOT | ||
| 40 | #define FR_EXLM KC_SLSH | ||
| 41 | |||
| 42 | // Shifted characters | ||
| 43 | #define FR_1 LSFT(KC_1) | ||
| 44 | #define FR_2 LSFT(KC_2) | ||
| 45 | #define FR_3 LSFT(KC_3) | ||
| 46 | #define FR_4 LSFT(KC_4) | ||
| 47 | #define FR_5 LSFT(KC_5) | ||
| 48 | #define FR_6 LSFT(KC_6) | ||
| 49 | #define FR_7 LSFT(KC_7) | ||
| 50 | #define FR_8 LSFT(KC_8) | ||
| 51 | #define FR_9 LSFT(KC_9) | ||
| 52 | #define FR_0 LSFT(KC_0) | ||
| 53 | #define FR_OVRR LSFT(FR_RPRN) | ||
| 54 | #define FR_PLUS LSFT(FR_EQL) | ||
| 55 | |||
| 56 | #define FR_UMLT LSFT(FR_CIRC) | ||
| 57 | #define FR_PND LSFT(FR_DLR) | ||
| 58 | #define FR_PERC LSFT(FR_UGRV) | ||
| 59 | #define FR_MU LSFT(FR_ASTR) | ||
| 60 | |||
| 61 | #define FR_GRTR LSFT(FR_LESS) | ||
| 62 | #define FR_QUES LSFT(FR_COMM) | ||
| 63 | #define FR_DOT LSFT(FR_SCLN) | ||
| 64 | #define FR_SLSH LSFT(FR_COLN) | ||
| 65 | #define FR_SECT LSFT(FR_EXLM) | ||
| 66 | |||
| 67 | // Alt Gr-ed characters | ||
| 68 | #define FR_TILD ALGR(KC_2) | ||
| 69 | #define FR_HASH ALGR(KC_3) | ||
| 70 | #define FR_LCBR ALGR(KC_4) | ||
| 71 | #define FR_LBRC ALGR(KC_5) | ||
| 72 | #define FR_PIPE ALGR(KC_6) | ||
| 73 | #define FR_GRV ALGR(KC_7) | ||
| 74 | #define FR_BSLS ALGR(KC_8) | ||
| 75 | #define FR_CIRC ALGR(KC_9) | ||
| 76 | #define FR_AT ALGR(KC_0) | ||
| 77 | #define FR_RBRC ALGR(FR_RPRN) | ||
| 78 | #define FR_RCBR ALGR(FR_EQL) | ||
| 79 | |||
| 80 | #define FR_EURO ALGR(KC_E) | ||
| 81 | #define FR_BULT ALGR(FR_DLR) | ||
| 82 | |||
| 83 | #endif \ No newline at end of file | ||
diff --git a/quantum/keymap_extras/keymap_french_osx.h b/quantum/keymap_extras/keymap_french_osx.h new file mode 100644 index 000000000..004d73ee2 --- /dev/null +++ b/quantum/keymap_extras/keymap_french_osx.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | #ifndef KEYMAP_FRENCH_OSX_H | ||
| 2 | #define KEYMAP_FRENCH_OSX_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Normal characters | ||
| 7 | #define FR_AT KC_GRV | ||
| 8 | #define FR_AMP KC_1 | ||
| 9 | #define FR_EACU KC_2 | ||
| 10 | #define FR_QUOT KC_3 | ||
| 11 | #define FR_APOS KC_4 | ||
| 12 | #define FR_LPRN KC_5 | ||
| 13 | #define FR_SECT KC_6 | ||
| 14 | #define FR_EGRV KC_7 | ||
| 15 | #define FR_EXLM KC_8 | ||
| 16 | #define FR_CCED KC_9 | ||
| 17 | #define FR_AGRV KC_0 | ||
| 18 | #define FR_RPRN KC_MINS | ||
| 19 | #define FR_MINS KC_EQL | ||
| 20 | |||
| 21 | #define FR_A KC_Q | ||
| 22 | #define FR_Z KC_W | ||
| 23 | #define FR_CIRC KC_LBRC | ||
| 24 | #define FR_DLR KC_RBRC | ||
| 25 | |||
| 26 | #define FR_Q KC_A | ||
| 27 | #define FR_M KC_SCLN | ||
| 28 | #define FR_UGRV KC_QUOT | ||
| 29 | #define FR_GRV KC_NUHS | ||
| 30 | |||
| 31 | #define FR_LESS KC_NUBS | ||
| 32 | #define FR_W KC_Z | ||
| 33 | #define FR_COMM KC_M | ||
| 34 | #define FR_SCLN KC_COMM | ||
| 35 | #define FR_COLN KC_DOT | ||
| 36 | #define FR_EQL KC_SLSH | ||
| 37 | |||
| 38 | // Shifted characters | ||
| 39 | #define FR_HASH LSFT(KC_GRV) | ||
| 40 | #define FR_1 LSFT(KC_1) | ||
| 41 | #define FR_2 LSFT(KC_2) | ||
| 42 | #define FR_3 LSFT(KC_3) | ||
| 43 | #define FR_4 LSFT(KC_4) | ||
| 44 | #define FR_5 LSFT(KC_5) | ||
| 45 | #define FR_6 LSFT(KC_6) | ||
| 46 | #define FR_7 LSFT(KC_7) | ||
| 47 | #define FR_8 LSFT(KC_8) | ||
| 48 | #define FR_9 LSFT(KC_9) | ||
| 49 | #define FR_0 LSFT(KC_0) | ||
| 50 | #define FR_UNDS LSFT(FR_MINS) | ||
| 51 | |||
| 52 | #define FR_UMLT LSFT(FR_CIRC) | ||
| 53 | #define FR_ASTR LSFT(FR_DLR) | ||
| 54 | |||
| 55 | #define FR_PERC LSFT(FR_UGRV) | ||
| 56 | #define FR_PND LSFT(FR_GRV) | ||
| 57 | |||
| 58 | #define FR_GRTR LSFT(FR_LESS) | ||
| 59 | #define FR_QUES LSFT(FR_COMM) | ||
| 60 | #define FR_DOT LSFT(FR_SCLN) | ||
| 61 | #define FR_SLSH LSFT(FR_COLN) | ||
| 62 | #define FR_PLUS LSFT(FR_EQL) | ||
| 63 | |||
| 64 | // Alted characters | ||
| 65 | #define FR_LCBR LALT(KC_5) | ||
| 66 | #define FR_RCBR LALT(FR_RPRN) | ||
| 67 | #define FR_EURO LALT(KC_E) | ||
| 68 | #define FR_BULT LALT(FR_DLR) | ||
| 69 | #define FR_TILD LALT(KC_N) | ||
| 70 | |||
| 71 | // Shift+Alt-ed characters | ||
| 72 | #define FR_LBRC LSFT(LALT(KC_5)) | ||
| 73 | #define FR_RBRC LSFT(LALT(FR_RPRN)) | ||
| 74 | #define FR_PIPE LSFT(LALT(KC_L)) | ||
| 75 | #define FR_BSLS LSFT(LALT(FR_COLN)) | ||
| 76 | |||
| 77 | #endif \ No newline at end of file | ||
diff --git a/quantum/keymap_extras/keymap_german.h b/quantum/keymap_extras/keymap_german.h new file mode 100644 index 000000000..3f9ae8bad --- /dev/null +++ b/quantum/keymap_extras/keymap_german.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | #ifndef KEYMAP_GERMAN | ||
| 2 | #define KEYMAP_GERMAN | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define DE_ALGR KC_RALT | ||
| 9 | |||
| 10 | // normal characters | ||
| 11 | #define DE_Z KC_Y | ||
| 12 | #define DE_Y KC_Z | ||
| 13 | |||
| 14 | #define DE_A KC_A | ||
| 15 | #define DE_B KC_B | ||
| 16 | #define DE_C KC_C | ||
| 17 | #define DE_D KC_D | ||
| 18 | #define DE_E KC_E | ||
| 19 | #define DE_F KC_F | ||
| 20 | #define DE_G KC_G | ||
| 21 | #define DE_H KC_H | ||
| 22 | #define DE_I KC_I | ||
| 23 | #define DE_J KC_J | ||
| 24 | #define DE_K KC_K | ||
| 25 | #define DE_L KC_L | ||
| 26 | #define DE_M KC_M | ||
| 27 | #define DE_N KC_N | ||
| 28 | #define DE_O KC_O | ||
| 29 | #define DE_P KC_P | ||
| 30 | #define DE_Q KC_Q | ||
| 31 | #define DE_R KC_R | ||
| 32 | #define DE_S KC_S | ||
| 33 | #define DE_T KC_T | ||
| 34 | #define DE_U KC_U | ||
| 35 | #define DE_V KC_V | ||
| 36 | #define DE_W KC_W | ||
| 37 | #define DE_X KC_X | ||
| 38 | |||
| 39 | #define DE_0 KC_0 | ||
| 40 | #define DE_1 KC_1 | ||
| 41 | #define DE_2 KC_2 | ||
| 42 | #define DE_3 KC_3 | ||
| 43 | #define DE_4 KC_4 | ||
| 44 | #define DE_5 KC_5 | ||
| 45 | #define DE_6 KC_6 | ||
| 46 | #define DE_7 KC_7 | ||
| 47 | #define DE_8 KC_8 | ||
| 48 | #define DE_9 KC_9 | ||
| 49 | |||
| 50 | #define DE_DOT KC_DOT | ||
| 51 | #define DE_COMM KC_COMM | ||
| 52 | |||
| 53 | #define DE_SS KC_MINS | ||
| 54 | #define DE_AE KC_QUOT | ||
| 55 | #define DE_UE KC_LBRC | ||
| 56 | #define DE_OE KC_SCLN | ||
| 57 | |||
| 58 | #define DE_CIRC KC_GRAVE // accent circumflex ^ and ring ° | ||
| 59 | #define DE_ACUT KC_EQL // accent acute ´ and grave ` | ||
| 60 | #define DE_PLUS KC_RBRC // + and * and ~ | ||
| 61 | #define DE_HASH KC_BSLS // # and ' | ||
| 62 | #define DE_LESS KC_NUBS // < and > and | | ||
| 63 | #define DE_MINS KC_SLSH // - and _ | ||
| 64 | |||
| 65 | // shifted characters | ||
| 66 | #define DE_RING LSFT(DE_CIRC) // ° | ||
| 67 | #define DE_EXLM LSFT(KC_1) // ! | ||
| 68 | #define DE_DQOT LSFT(KC_2) // " | ||
| 69 | #define DE_PARA LSFT(KC_3) // § | ||
| 70 | #define DE_DLR LSFT(KC_4) // $ | ||
| 71 | #define DE_PERC LSFT(KC_5) // % | ||
| 72 | #define DE_AMPR LSFT(KC_6) // & | ||
| 73 | #define DE_SLSH LSFT(KC_7) // / | ||
| 74 | #define DE_LPRN LSFT(KC_8) // ( | ||
| 75 | #define DE_RPRN LSFT(KC_9) // ) | ||
| 76 | #define DE_EQL LSFT(KC_0) // = | ||
| 77 | #define DE_QST LSFT(DE_SS) // ? | ||
| 78 | #define DE_GRV LSFT(DE_ACUT) // ` | ||
| 79 | #define DE_ASTR LSFT(DE_PLUS) // * | ||
| 80 | #define DE_QUOT LSFT(DE_HASH) // ' | ||
| 81 | #define DE_MORE LSFT(DE_LESS) // > | ||
| 82 | #define DE_COLN LSFT(KC_DOT) // : | ||
| 83 | #define DE_SCLN LSFT(KC_COMM) // ; | ||
| 84 | #define DE_UNDS LSFT(DE_MINS) // _ | ||
| 85 | |||
| 86 | // Alt Gr-ed characters | ||
| 87 | #define DE_SQ2 ALGR(KC_2) // ² | ||
| 88 | #define DE_SQ3 ALGR(KC_3) // ³ | ||
| 89 | #define DE_LCBR ALGR(KC_7) // { | ||
| 90 | #define DE_LBRC ALGR(KC_8) // [ | ||
| 91 | #define DE_RBRC ALGR(KC_9) // ] | ||
| 92 | #define DE_RCBR ALGR(KC_0) // } | ||
| 93 | #define DE_BSLS ALGR(DE_SS) // backslash | ||
| 94 | #define DE_AT ALGR(KC_Q) // @ | ||
| 95 | #define DE_EURO ALGR(KC_E) // € | ||
| 96 | #define DE_TILD ALGR(DE_PLUS) // ~ | ||
| 97 | #define DE_PIPE ALGR(DE_LESS) // | | ||
| 98 | |||
| 99 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_german_ch.h b/quantum/keymap_extras/keymap_german_ch.h new file mode 100644 index 000000000..6a782bcd7 --- /dev/null +++ b/quantum/keymap_extras/keymap_german_ch.h | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #ifndef KEYMAP_SWISS_GERMAN | ||
| 2 | #define KEYMAP_SWISS_GERMAN | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define CH_ALGR KC_RALT | ||
| 9 | |||
| 10 | // normal characters | ||
| 11 | #define CH_Z KC_Y | ||
| 12 | #define CH_Y KC_Z | ||
| 13 | |||
| 14 | #define CH_A KC_A | ||
| 15 | #define CH_B KC_B | ||
| 16 | #define CH_C KC_C | ||
| 17 | #define CH_D KC_D | ||
| 18 | #define CH_E KC_E | ||
| 19 | #define CH_F KC_F | ||
| 20 | #define CH_G KC_G | ||
| 21 | #define CH_H KC_H | ||
| 22 | #define CH_I KC_I | ||
| 23 | #define CH_J KC_J | ||
| 24 | #define CH_K KC_K | ||
| 25 | #define CH_L KC_L | ||
| 26 | #define CH_M KC_M | ||
| 27 | #define CH_N KC_N | ||
| 28 | #define CH_O KC_O | ||
| 29 | #define CH_P KC_P | ||
| 30 | #define CH_Q KC_Q | ||
| 31 | #define CH_R KC_R | ||
| 32 | #define CH_S KC_S | ||
| 33 | #define CH_T KC_T | ||
| 34 | #define CH_U KC_U | ||
| 35 | #define CH_V KC_V | ||
| 36 | #define CH_W KC_W | ||
| 37 | #define CH_X KC_X | ||
| 38 | |||
| 39 | #define CH_0 KC_0 | ||
| 40 | #define CH_1 KC_1 | ||
| 41 | #define CH_2 KC_2 | ||
| 42 | #define CH_3 KC_3 | ||
| 43 | #define CH_4 KC_4 | ||
| 44 | #define CH_5 KC_5 | ||
| 45 | #define CH_6 KC_6 | ||
| 46 | #define CH_7 KC_7 | ||
| 47 | #define CH_8 KC_8 | ||
| 48 | #define CH_9 KC_9 | ||
| 49 | |||
| 50 | #define CH_DOT KC_DOT | ||
| 51 | #define CH_COMM KC_COMM | ||
| 52 | |||
| 53 | #define CH_QUOT KC_MINS // ' ? ´ | ||
| 54 | #define CH_AE KC_QUOT | ||
| 55 | #define CH_UE KC_LBRC | ||
| 56 | #define CH_OE KC_SCLN | ||
| 57 | |||
| 58 | #define CH_PARA KC_GRAVE // secction sign § and ° | ||
| 59 | #define CH_CARR KC_EQL // carret ^ ` ~ | ||
| 60 | #define CH_DIER KC_RBRC // dieresis ¨ ! ] | ||
| 61 | #define CH_DLR KC_BSLS // $ £ } | ||
| 62 | #define CH_LESS KC_NUBS // < and > and backslash | ||
| 63 | #define CH_MINS KC_SLSH // - and _ | ||
| 64 | |||
| 65 | // shifted characters | ||
| 66 | #define CH_RING LSFT(CH_PARA) // ° | ||
| 67 | #define CH_PLUS LSFT(KC_1) // + | ||
| 68 | #define CH_DQOT LSFT(KC_2) // " | ||
| 69 | #define CH_PAST LSFT(KC_3) // * | ||
| 70 | #define CH_CELA LSFT(KC_4) // ç | ||
| 71 | #define CH_PERC LSFT(KC_5) // % | ||
| 72 | #define CH_AMPR LSFT(KC_6) // & | ||
| 73 | #define CH_SLSH LSFT(KC_7) // / | ||
| 74 | #define CH_LPRN LSFT(KC_8) // ( | ||
| 75 | #define CH_RPRN LSFT(KC_9) // ) | ||
| 76 | #define CH_EQL LSFT(KC_0) // = | ||
| 77 | #define CH_QST LSFT(CH_QUOT) // ? | ||
| 78 | #define CH_GRV LSFT(CH_CARR) // ` | ||
| 79 | #define CH_EXLM LSFT(CH_DIER) // ! | ||
| 80 | #define CH_POND LSFT(CH_DLR) // £ | ||
| 81 | #define CH_MORE LSFT(CH_LESS) // > | ||
| 82 | #define CH_COLN LSFT(KC_DOT) // : | ||
| 83 | #define CH_SCLN LSFT(KC_COMM) // ; | ||
| 84 | #define CH_UNDS LSFT(CH_MINS) // _ | ||
| 85 | |||
| 86 | // Alt Gr-ed characters | ||
| 87 | #define CH_BRBR ALGR(KC_1) // ¦ brocken bar | ||
| 88 | #define CH_AT ALGR(KC_2) // @ | ||
| 89 | #define CH_HASH ALGR(KC_3) // # | ||
| 90 | #define CH_NOTL ALGR(KC_6) // ¬ negative logic | ||
| 91 | #define CH_PIPE ALGR(KC_7) // | | ||
| 92 | #define CH_CENT ALGR(KC_8) // ¢ cent | ||
| 93 | #define CH_ACUT ALGR(CH_QUOT) // ´ | ||
| 94 | #define CH_TILD ALGR(CH_CARR) // ~ | ||
| 95 | #define CH_EURO ALGR(KC_E) // € | ||
| 96 | #define CH_LBRC ALGR(CH_UE) // [ | ||
| 97 | #define CH_RBRC ALGR(CH_DIER) // ] | ||
| 98 | #define CH_LCBR ALGR(CH_AE) // { | ||
| 99 | #define CH_RCBR ALGR(CH_DLR) // } | ||
| 100 | #define CH_BSLS ALGR(CH_LESS) // backslash | ||
| 101 | |||
| 102 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_german_osx.h b/quantum/keymap_extras/keymap_german_osx.h new file mode 100644 index 000000000..f63f06618 --- /dev/null +++ b/quantum/keymap_extras/keymap_german_osx.h | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #ifndef KEYMAP_GERMAN_OSX | ||
| 2 | #define KEYMAP_GERMAN_OSX | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | |||
| 8 | // normal characters | ||
| 9 | #define DE_OSX_Z KC_Y | ||
| 10 | #define DE_OSX_Y KC_Z | ||
| 11 | |||
| 12 | #define DE_OSX_A KC_A | ||
| 13 | #define DE_OSX_B KC_B | ||
| 14 | #define DE_OSX_C KC_C | ||
| 15 | #define DE_OSX_D KC_D | ||
| 16 | #define DE_OSX_E KC_E | ||
| 17 | #define DE_OSX_F KC_F | ||
| 18 | #define DE_OSX_G KC_G | ||
| 19 | #define DE_OSX_H KC_H | ||
| 20 | #define DE_OSX_I KC_I | ||
| 21 | #define DE_OSX_J KC_J | ||
| 22 | #define DE_OSX_K KC_K | ||
| 23 | #define DE_OSX_L KC_L | ||
| 24 | #define DE_OSX_M KC_M | ||
| 25 | #define DE_OSX_N KC_N | ||
| 26 | #define DE_OSX_O KC_O | ||
| 27 | #define DE_OSX_P KC_P | ||
| 28 | #define DE_OSX_Q KC_Q | ||
| 29 | #define DE_OSX_R KC_R | ||
| 30 | #define DE_OSX_S KC_S | ||
| 31 | #define DE_OSX_T KC_T | ||
| 32 | #define DE_OSX_U KC_U | ||
| 33 | #define DE_OSX_V KC_V | ||
| 34 | #define DE_OSX_W KC_W | ||
| 35 | #define DE_OSX_X KC_X | ||
| 36 | |||
| 37 | #define DE_OSX_0 KC_0 | ||
| 38 | #define DE_OSX_1 KC_1 | ||
| 39 | #define DE_OSX_2 KC_2 | ||
| 40 | #define DE_OSX_3 KC_3 | ||
| 41 | #define DE_OSX_4 KC_4 | ||
| 42 | #define DE_OSX_5 KC_5 | ||
| 43 | #define DE_OSX_6 KC_6 | ||
| 44 | #define DE_OSX_7 KC_7 | ||
| 45 | #define DE_OSX_8 KC_8 | ||
| 46 | #define DE_OSX_9 KC_9 | ||
| 47 | |||
| 48 | #define DE_OSX_DOT KC_DOT | ||
| 49 | #define DE_OSX_COMM KC_COMM | ||
| 50 | |||
| 51 | #define DE_OSX_SS KC_MINS | ||
| 52 | #define DE_OSX_AE KC_QUOT | ||
| 53 | #define DE_OSX_UE KC_LBRC | ||
| 54 | #define DE_OSX_OE KC_SCLN | ||
| 55 | |||
| 56 | #define DE_OSX_CIRC KC_NUBS // accent circumflex ^ and ring ° | ||
| 57 | #define DE_OSX_ACUT KC_EQL // accent acute ´ and grave ` | ||
| 58 | #define DE_OSX_PLUS KC_RBRC // + and * and ~ | ||
| 59 | #define DE_OSX_HASH KC_BSLS // # and ' | ||
| 60 | #define DE_OSX_LESS KC_GRV // < and > and | | ||
| 61 | #define DE_OSX_MINS KC_SLSH // - and _ | ||
| 62 | |||
| 63 | // shifted characters | ||
| 64 | #define DE_OSX_RING LSFT(DE_OSX_CIRC) // ° | ||
| 65 | #define DE_OSX_EXLM LSFT(KC_1) // ! | ||
| 66 | #define DE_OSX_DQOT LSFT(KC_2) // " | ||
| 67 | #define DE_OSX_PARA LSFT(KC_3) // § | ||
| 68 | #define DE_OSX_DLR LSFT(KC_4) // $ | ||
| 69 | #define DE_OSX_PERC LSFT(KC_5) // % | ||
| 70 | #define DE_OSX_AMPR LSFT(KC_6) // & | ||
| 71 | #define DE_OSX_SLSH LSFT(KC_7) // / | ||
| 72 | #define DE_OSX_LPRN LSFT(KC_8) // ( | ||
| 73 | #define DE_OSX_RPRN LSFT(KC_9) // ) | ||
| 74 | #define DE_OSX_EQL LSFT(KC_0) // = | ||
| 75 | #define DE_OSX_QST LSFT(DE_OSX_SS) // ? | ||
| 76 | #define DE_OSX_GRV LSFT(DE_OSX_ACUT) // ` | ||
| 77 | #define DE_OSX_ASTR LSFT(DE_OSX_PLUS) // * | ||
| 78 | #define DE_OSX_QUOT LSFT(DE_OSX_HASH) // ' | ||
| 79 | #define DE_OSX_MORE LSFT(DE_OSX_LESS) // > | ||
| 80 | #define DE_OSX_COLN LSFT(KC_DOT) // : | ||
| 81 | #define DE_OSX_SCLN LSFT(KC_COMM) // ; | ||
| 82 | #define DE_OSX_UNDS LSFT(DE_OSX_MINS) // _ | ||
| 83 | |||
| 84 | // Alt-ed characters | ||
| 85 | //#define DE_OSX_SQ2 LALT(KC_2) // ² | ||
| 86 | //#define DE_OSX_SQ3 LALT(KC_3) // ³ | ||
| 87 | #define DE_OSX_LCBR LALT(KC_8) // { | ||
| 88 | #define DE_OSX_LBRC LALT(KC_5) // [ | ||
| 89 | #define DE_OSX_RBRC LALT(KC_6) // ] | ||
| 90 | #define DE_OSX_RCBR LALT(KC_9) // } | ||
| 91 | #define DE_OSX_BSLS LALT(LSFT(KC_7)) // backslash | ||
| 92 | #define DE_OSX_AT LALT(DE_OSX_L) // @ | ||
| 93 | #define DE_OSX_EURO LALT(KC_E) // € | ||
| 94 | #define DE_OSX_TILD LALT(DE_OSX_N) // ~ | ||
| 95 | #define DE_OSX_PIPE LALT(DE_OSX_7) // | | ||
| 96 | |||
| 97 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_neo2.h b/quantum/keymap_extras/keymap_neo2.h new file mode 100644 index 000000000..80439af34 --- /dev/null +++ b/quantum/keymap_extras/keymap_neo2.h | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | #ifndef KEYMAP_NEO2 | ||
| 2 | #define KEYMAP_NEO2 | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | #include "keymap_german.h" | ||
| 6 | |||
| 7 | #define NEO_A KC_D | ||
| 8 | #define NEO_B KC_N | ||
| 9 | #define NEO_C KC_R | ||
| 10 | #define NEO_D DE_OE | ||
| 11 | #define NEO_E KC_F | ||
| 12 | #define NEO_F KC_O | ||
| 13 | #define NEO_G KC_I | ||
| 14 | #define NEO_H KC_U | ||
| 15 | #define NEO_I KC_S | ||
| 16 | #define NEO_J DE_MINS | ||
| 17 | #define NEO_K DE_Z | ||
| 18 | #define NEO_L KC_E | ||
| 19 | #define NEO_M KC_M | ||
| 20 | #define NEO_N KC_J | ||
| 21 | #define NEO_O KC_G | ||
| 22 | #define NEO_P KC_V | ||
| 23 | #define NEO_Q KC_P | ||
| 24 | #define NEO_R KC_K | ||
| 25 | #define NEO_S KC_H | ||
| 26 | #define NEO_T KC_L | ||
| 27 | #define NEO_U KC_A | ||
| 28 | #define NEO_V KC_W | ||
| 29 | #define NEO_W KC_T | ||
| 30 | #define NEO_X KC_Q | ||
| 31 | #define NEO_Y DE_AE | ||
| 32 | #define NEO_Z KC_B | ||
| 33 | #define NEO_AE KC_C | ||
| 34 | #define NEO_OE KC_X | ||
| 35 | #define NEO_UE DE_Y | ||
| 36 | #define NEO_SS DE_UE | ||
| 37 | |||
| 38 | #define NEO_DOT DE_DOT | ||
| 39 | #define NEO_COMM DE_COMM | ||
| 40 | |||
| 41 | #define NEO_1 DE_1 | ||
| 42 | #define NEO_2 DE_2 | ||
| 43 | #define NEO_3 DE_3 | ||
| 44 | #define NEO_4 DE_4 | ||
| 45 | #define NEO_5 DE_5 | ||
| 46 | #define NEO_6 DE_6 | ||
| 47 | #define NEO_7 DE_7 | ||
| 48 | #define NEO_8 DE_8 | ||
| 49 | #define NEO_9 DE_9 | ||
| 50 | #define NEO_0 DE_0 | ||
| 51 | #define NEO_MINS DE_SS | ||
| 52 | |||
| 53 | #define NEO_ACUT DE_PLUS | ||
| 54 | #define NEO_GRV DE_ACUT | ||
| 55 | #define NEO_CIRC DE_CIRC | ||
| 56 | |||
| 57 | #define NEO_L1_L KC_CAPS | ||
| 58 | #define NEO_L1_R DE_HASH | ||
| 59 | |||
| 60 | #define NEO_L2_L DE_LESS | ||
| 61 | #define NEO_L2_R DE_ALGR | ||
| 62 | |||
| 63 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h new file mode 100644 index 000000000..3acb8b698 --- /dev/null +++ b/quantum/keymap_extras/keymap_nordic.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #ifndef KEYMAP_NORDIC_H | ||
| 2 | #define KEYMAP_NORDIC_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define NO_ALGR KC_RALT | ||
| 9 | |||
| 10 | // Normal characters | ||
| 11 | #define NO_HALF KC_GRV | ||
| 12 | #define NO_PLUS KC_MINS | ||
| 13 | #define NO_ACUT KC_EQL | ||
| 14 | |||
| 15 | #define NO_AM KC_LBRC | ||
| 16 | #define NO_QUOT KC_RBRC | ||
| 17 | #define NO_AE KC_SCLN | ||
| 18 | #define NO_OSLH KC_QUOT | ||
| 19 | #define NO_APOS KC_NUHS | ||
| 20 | |||
| 21 | #define NO_LESS KC_NUBS | ||
| 22 | #define NO_MINS KC_SLSH | ||
| 23 | |||
| 24 | // Shifted characters | ||
| 25 | #define NO_SECT LSFT(NO_HALF) | ||
| 26 | #define NO_QUO2 LSFT(KC_2) | ||
| 27 | #define NO_BULT LSFT(KC_4) | ||
| 28 | #define NO_AMP LSFT(KC_6) | ||
| 29 | #define NO_SLSH LSFT(KC_7) | ||
| 30 | #define NO_LPRN LSFT(KC_8) | ||
| 31 | #define NO_RPRN LSFT(KC_9) | ||
| 32 | #define NO_EQL LSFT(KC_0) | ||
| 33 | #define NO_QUES LSFT(NO_PLUS) | ||
| 34 | #define NO_GRV LSFT(NO_ACUT) | ||
| 35 | |||
| 36 | #define NO_CIRC LSFT(NO_QUOT) | ||
| 37 | |||
| 38 | #define NO_GRTR LSFT(NO_LESS) | ||
| 39 | #define NO_SCLN LSFT(KC_COMM) | ||
| 40 | #define NO_COLN LSFT(KC_DOT) | ||
| 41 | #define NO_UNDS LSFT(NO_MINS) | ||
| 42 | |||
| 43 | // Alt Gr-ed characters | ||
| 44 | #define NO_AT ALGR(KC_2) | ||
| 45 | #define NO_PND ALGR(KC_3) | ||
| 46 | #define NO_DLR ALGR(KC_4) | ||
| 47 | #define NO_LCBR ALGR(KC_7) | ||
| 48 | #define NO_LBRC ALGR(KC_8) | ||
| 49 | #define NO_RBRC ALGR(KC_9) | ||
| 50 | #define NO_RCBR ALGR(KC_0) | ||
| 51 | #define NO_PIPE ALGR(KC_NUBS) | ||
| 52 | |||
| 53 | #define NO_EURO ALGR(KC_E) | ||
| 54 | #define NO_TILD ALGR(NO_QUOT) | ||
| 55 | |||
| 56 | #define NO_BSLS ALGR(KC_MINS) | ||
| 57 | #define NO_MU ALGR(KC_M) | ||
| 58 | |||
| 59 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h new file mode 100644 index 000000000..018bfeae5 --- /dev/null +++ b/quantum/keymap_extras/keymap_norwegian.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef KEYMAP_NORWEGIAN_H | ||
| 2 | #define KEYMAP_NORWEGIAN_H | ||
| 3 | |||
| 4 | #include "keymap_nordic.h" | ||
| 5 | |||
| 6 | // There are slight differrences in the keyboards in the nordic contries | ||
| 7 | |||
| 8 | // Norwegian redifinitions from the nordic keyset | ||
| 9 | #undef NO_ACUT | ||
| 10 | #define NO_ACUT ALGR(NO_BSLS) // ´ | ||
| 11 | #undef NO_AE | ||
| 12 | #define NO_AE KC_QUOT // æ | ||
| 13 | #undef NO_BSLS | ||
| 14 | #define NO_BSLS KC_EQL // '\' | ||
| 15 | #undef NO_CIRC | ||
| 16 | #define NO_CIRC LSFT(C_RBRC) // ^ | ||
| 17 | #undef NO_GRV | ||
| 18 | #define NO_GRV LSFT(NO_BSLS) // | ||
| 19 | #undef NO_OSLH | ||
| 20 | #define NO_OSLH KC_SCLN // ø | ||
| 21 | #undef NO_PIPE | ||
| 22 | #define NO_PIPE KC_GRV // | | ||
| 23 | |||
| 24 | // Additional norwegian keys not defined in the nordic keyset | ||
| 25 | #define NO_AA KC_LBRC // å | ||
| 26 | #define NO_ASTR LSFT(KC_BSLS) // * | ||
| 27 | |||
| 28 | // Norwegian unique MAC characters | ||
| 29 | #define NO_ACUT_MAC KC_EQL // = | ||
| 30 | #define NO_APOS_MAC KC_NUBS // ' | ||
| 31 | #define NO_AT_MAC KC_BSLS // @ | ||
| 32 | #define NO_BSLS_MAC ALGR(LSFT(KC_7)) // '\' | ||
| 33 | #define NO_DLR_MAC LSFT(KC_4) // $ | ||
| 34 | #define NO_GRV_MAC ALGR(NO_BSLS) // ` | ||
| 35 | #define NO_GRTR_MAC LSFT(KC_GRV) // > | ||
| 36 | #define NO_LCBR_MAC ALGR(LSFT(KC_8)) // } | ||
| 37 | #define NO_LESS_MAC KC_GRV // > | ||
| 38 | #define NO_PIPE_MAC ALGR(KC_7) // | | ||
| 39 | #define NO_RCBR_MAC ALGR(LSFT(KC_9)) // } | ||
| 40 | |||
| 41 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_plover.h b/quantum/keymap_extras/keymap_plover.h new file mode 100644 index 000000000..9b88f7d84 --- /dev/null +++ b/quantum/keymap_extras/keymap_plover.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | #ifndef KEYMAP_PLOVER_H | ||
| 2 | #define KEYMAP_PLOVER_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | #define PV_NUM KC_1 | ||
| 7 | #define PV_LS KC_Q | ||
| 8 | #define PV_LT KC_W | ||
| 9 | #define PV_LP KC_E | ||
| 10 | #define PV_LH KC_R | ||
| 11 | #define PV_LK KC_S | ||
| 12 | #define PV_LW KC_D | ||
| 13 | #define PV_LR KC_F | ||
| 14 | |||
| 15 | #define PV_STAR KC_Y | ||
| 16 | #define PV_RF KC_U | ||
| 17 | #define PV_RP KC_I | ||
| 18 | #define PV_RL KC_O | ||
| 19 | #define PV_RT KC_P | ||
| 20 | #define PV_RD KC_LBRC | ||
| 21 | #define PV_RR KC_J | ||
| 22 | #define PV_RB KC_K | ||
| 23 | #define PV_RG KC_L | ||
| 24 | #define PV_RS KC_SCLN | ||
| 25 | #define PV_RZ KC_QUOT | ||
| 26 | |||
| 27 | #define PV_A KC_C | ||
| 28 | #define PV_O KC_V | ||
| 29 | #define PV_E KC_N | ||
| 30 | #define PV_U KC_M | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_spanish.h b/quantum/keymap_extras/keymap_spanish.h new file mode 100644 index 000000000..af76e39fc --- /dev/null +++ b/quantum/keymap_extras/keymap_spanish.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | #ifndef KEYMAP_SPANISH_H | ||
| 2 | #define KEYMAP_SPANISH_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define NO_ALGR KC_RALT | ||
| 9 | |||
| 10 | // Normal characters | ||
| 11 | #define ES_OVRR KC_GRV | ||
| 12 | #define ES_APOS KC_MINS | ||
| 13 | #define ES_IEXL KC_EQL | ||
| 14 | |||
| 15 | #define ES_GRV KC_LBRC | ||
| 16 | #define ES_PLUS KC_RBRC | ||
| 17 | |||
| 18 | #define ES_NTIL KC_SCLN | ||
| 19 | #define ES_ACUT KC_QUOT | ||
| 20 | #define ES_CCED KC_NUHS | ||
| 21 | |||
| 22 | #define ES_LESS KC_NUBS | ||
| 23 | #define ES_MINS KC_SLSH | ||
| 24 | |||
| 25 | // Shifted characters | ||
| 26 | #define ES_ASML LSFT(ES_OVRR) | ||
| 27 | #define ES_QUOT LSFT(KC_2) | ||
| 28 | #define ES_OVDT LSFT(KC_3) | ||
| 29 | #define ES_AMPR LSFT(KC_6) | ||
| 30 | #define ES_SLSH LSFT(KC_7) | ||
| 31 | #define ES_LPRN LSFT(KC_8) | ||
| 32 | #define ES_RPRN LSFT(KC_9) | ||
| 33 | #define ES_EQL LSFT(KC_0) | ||
| 34 | #define ES_QUES LSFT(ES_APOS) | ||
| 35 | #define ES_IQUE LSFT(ES_IEXL) | ||
| 36 | |||
| 37 | #define ES_CIRC LSFT(ES_GRV) | ||
| 38 | #define ES_ASTR LSFT(ES_PLUS) | ||
| 39 | |||
| 40 | #define ES_UMLT LSFT(ES_GRV) | ||
| 41 | |||
| 42 | #define ES_GRTR LSFT(ES_LESS) | ||
| 43 | #define ES_SCLN LSFT(ES_COMM) | ||
| 44 | #define ES_COLN LSFT(ES_DOT) | ||
| 45 | #define ES_UNDS LSFT(ES_MINS) | ||
| 46 | |||
| 47 | // Alt Gr-ed characters | ||
| 48 | #define ES_BSLS ALGR(ES_OVRR) | ||
| 49 | #define ES_PIPE ALGR(KC_1) | ||
| 50 | #define ES_AT ALGR(KC_2) | ||
| 51 | #define ES_HASH ALGR(KC_3) | ||
| 52 | #define ES_TILD ALGR(ES_NTIL) | ||
| 53 | #define ES_EURO ALGR(KC_5) | ||
| 54 | #define ES_NOT ALGR(KC_6) | ||
| 55 | |||
| 56 | #define ES_LBRC ALGR(ES_GRV) | ||
| 57 | #define ES_RBRC ALGR(ES_PLUS) | ||
| 58 | |||
| 59 | #define ES_LCBR ALGR(ES_ACUT) | ||
| 60 | #define ES_RCRB ALGR(ES_CCED) | ||
| 61 | |||
| 62 | #endif | ||
diff --git a/quantum/keymap_extras/keymap_uk.h b/quantum/keymap_extras/keymap_uk.h new file mode 100644 index 000000000..5c5d95179 --- /dev/null +++ b/quantum/keymap_extras/keymap_uk.h | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #ifndef KEYMAP_UK_H | ||
| 2 | #define KEYMAP_UK_H | ||
| 3 | |||
| 4 | #include "keymap.h" | ||
| 5 | |||
| 6 | // Alt gr | ||
| 7 | #define ALGR(kc) kc | 0x1400 | ||
| 8 | #define NO_ALGR KC_RALT | ||
| 9 | |||
| 10 | // Normal characters | ||
| 11 | #define UK_HASH KC_NUHS | ||
| 12 | |||
| 13 | #define UK_BSLS KC_NUBS | ||
| 14 | |||
| 15 | // Shifted characters | ||
| 16 | #define UK_NOT LSFT(KC_GRV) | ||
| 17 | #define UK_QUOT LSFT(KC_2) | ||
| 18 | #define UK_PND LSFT(KC_3) | ||
| 19 | |||
| 20 | #define UK_AT LSFT(KC_QUOT) | ||
| 21 | #define UK_TILD LSFT(KC_NUHS) | ||
| 22 | |||
| 23 | #define UK_PIPE LSFT(KC_NUBS) | ||
| 24 | |||
| 25 | // Alt Gr-ed characters | ||
| 26 | #define UK_BRKP ALGR(KC_GRV) | ||
| 27 | #define UK_EURO ALGR(KC_4) | ||
| 28 | |||
| 29 | #define UK_EACT ALGR(KC_E) | ||
| 30 | #define UK_UACT ALGR(KC_U) | ||
| 31 | #define UK_IACT ALGR(KC_I) | ||
| 32 | #define UK_OACT ALGR(KC_O) | ||
| 33 | |||
| 34 | #define UK_AACT ALGR(KC_A) | ||
| 35 | |||
| 36 | #endif \ No newline at end of file | ||
diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c new file mode 100755 index 000000000..f20043067 --- /dev/null +++ b/quantum/light_ws2812.c | |||
| @@ -0,0 +1,181 @@ | |||
| 1 | /* | ||
| 2 | * light weight WS2812 lib V2.0b | ||
| 3 | * | ||
| 4 | * Controls WS2811/WS2812/WS2812B RGB-LEDs | ||
| 5 | * Author: Tim (cpldcpu@gmail.com) | ||
| 6 | * | ||
| 7 | * Jan 18th, 2014 v2.0b Initial Version | ||
| 8 | * Nov 29th, 2015 v2.3 Added SK6812RGBW support | ||
| 9 | * | ||
| 10 | * License: GNU GPL v2 (see License.txt) | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "light_ws2812.h" | ||
| 14 | #include <avr/interrupt.h> | ||
| 15 | #include <avr/io.h> | ||
| 16 | #include <util/delay.h> | ||
| 17 | #include "debug.h" | ||
| 18 | |||
| 19 | // Setleds for standard RGB | ||
| 20 | void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) | ||
| 21 | { | ||
| 22 | ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); | ||
| 23 | } | ||
| 24 | |||
| 25 | void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) | ||
| 26 | { | ||
| 27 | ws2812_DDRREG |= pinmask; // Enable DDR | ||
| 28 | ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); | ||
| 29 | _delay_us(50); | ||
| 30 | } | ||
| 31 | |||
| 32 | // Setleds for SK6812RGBW | ||
| 33 | void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) | ||
| 34 | { | ||
| 35 | ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR | ||
| 36 | ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin)); | ||
| 37 | _delay_us(80); | ||
| 38 | } | ||
| 39 | |||
| 40 | void ws2812_sendarray(uint8_t *data,uint16_t datlen) | ||
| 41 | { | ||
| 42 | ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin)); | ||
| 43 | } | ||
| 44 | |||
| 45 | /* | ||
| 46 | This routine writes an array of bytes with RGB values to the Dataout pin | ||
| 47 | using the fast 800kHz clockless WS2811/2812 protocol. | ||
| 48 | */ | ||
| 49 | |||
| 50 | // Timing in ns | ||
| 51 | #define w_zeropulse 350 | ||
| 52 | #define w_onepulse 900 | ||
| 53 | #define w_totalperiod 1250 | ||
| 54 | |||
| 55 | // Fixed cycles used by the inner loop | ||
| 56 | #define w_fixedlow 2 | ||
| 57 | #define w_fixedhigh 4 | ||
| 58 | #define w_fixedtotal 8 | ||
| 59 | |||
| 60 | // Insert NOPs to match the timing, if possible | ||
| 61 | #define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000) | ||
| 62 | #define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000) | ||
| 63 | #define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000) | ||
| 64 | |||
| 65 | // w1 - nops between rising edge and falling edge - low | ||
| 66 | #define w1 (w_zerocycles-w_fixedlow) | ||
| 67 | // w2 nops between fe low and fe high | ||
| 68 | #define w2 (w_onecycles-w_fixedhigh-w1) | ||
| 69 | // w3 nops to complete loop | ||
| 70 | #define w3 (w_totalcycles-w_fixedtotal-w1-w2) | ||
| 71 | |||
| 72 | #if w1>0 | ||
| 73 | #define w1_nops w1 | ||
| 74 | #else | ||
| 75 | #define w1_nops 0 | ||
| 76 | #endif | ||
| 77 | |||
| 78 | // The only critical timing parameter is the minimum pulse length of the "0" | ||
| 79 | // Warn or throw error if this timing can not be met with current F_CPU settings. | ||
| 80 | #define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000) | ||
| 81 | #if w_lowtime>550 | ||
| 82 | #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" | ||
| 83 | #elif w_lowtime>450 | ||
| 84 | #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." | ||
| 85 | #warning "Please consider a higher clockspeed, if possible" | ||
| 86 | #endif | ||
| 87 | |||
| 88 | #if w2>0 | ||
| 89 | #define w2_nops w2 | ||
| 90 | #else | ||
| 91 | #define w2_nops 0 | ||
| 92 | #endif | ||
| 93 | |||
| 94 | #if w3>0 | ||
| 95 | #define w3_nops w3 | ||
| 96 | #else | ||
| 97 | #define w3_nops 0 | ||
| 98 | #endif | ||
| 99 | |||
| 100 | #define w_nop1 "nop \n\t" | ||
| 101 | #define w_nop2 "rjmp .+0 \n\t" | ||
| 102 | #define w_nop4 w_nop2 w_nop2 | ||
| 103 | #define w_nop8 w_nop4 w_nop4 | ||
| 104 | #define w_nop16 w_nop8 w_nop8 | ||
| 105 | |||
| 106 | void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) | ||
| 107 | { | ||
| 108 | uint8_t curbyte,ctr,masklo; | ||
| 109 | uint8_t sreg_prev; | ||
| 110 | |||
| 111 | masklo =~maskhi&ws2812_PORTREG; | ||
| 112 | maskhi |= ws2812_PORTREG; | ||
| 113 | sreg_prev=SREG; | ||
| 114 | cli(); | ||
| 115 | |||
| 116 | while (datlen--) { | ||
| 117 | curbyte=*data++; | ||
| 118 | |||
| 119 | asm volatile( | ||
| 120 | " ldi %0,8 \n\t" | ||
| 121 | "loop%=: \n\t" | ||
| 122 | " out %2,%3 \n\t" // '1' [01] '0' [01] - re | ||
| 123 | #if (w1_nops&1) | ||
| 124 | w_nop1 | ||
| 125 | #endif | ||
| 126 | #if (w1_nops&2) | ||
| 127 | w_nop2 | ||
| 128 | #endif | ||
| 129 | #if (w1_nops&4) | ||
| 130 | w_nop4 | ||
| 131 | #endif | ||
| 132 | #if (w1_nops&8) | ||
| 133 | w_nop8 | ||
| 134 | #endif | ||
| 135 | #if (w1_nops&16) | ||
| 136 | w_nop16 | ||
| 137 | #endif | ||
| 138 | " sbrs %1,7 \n\t" // '1' [03] '0' [02] | ||
| 139 | " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low | ||
| 140 | " lsl %1 \n\t" // '1' [04] '0' [04] | ||
| 141 | #if (w2_nops&1) | ||
| 142 | w_nop1 | ||
| 143 | #endif | ||
| 144 | #if (w2_nops&2) | ||
| 145 | w_nop2 | ||
| 146 | #endif | ||
| 147 | #if (w2_nops&4) | ||
| 148 | w_nop4 | ||
| 149 | #endif | ||
| 150 | #if (w2_nops&8) | ||
| 151 | w_nop8 | ||
| 152 | #endif | ||
| 153 | #if (w2_nops&16) | ||
| 154 | w_nop16 | ||
| 155 | #endif | ||
| 156 | " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high | ||
| 157 | #if (w3_nops&1) | ||
| 158 | w_nop1 | ||
| 159 | #endif | ||
| 160 | #if (w3_nops&2) | ||
| 161 | w_nop2 | ||
| 162 | #endif | ||
| 163 | #if (w3_nops&4) | ||
| 164 | w_nop4 | ||
| 165 | #endif | ||
| 166 | #if (w3_nops&8) | ||
| 167 | w_nop8 | ||
| 168 | #endif | ||
| 169 | #if (w3_nops&16) | ||
| 170 | w_nop16 | ||
| 171 | #endif | ||
| 172 | |||
| 173 | " dec %0 \n\t" // '1' [+2] '0' [+2] | ||
| 174 | " brne loop%=\n\t" // '1' [+3] '0' [+4] | ||
| 175 | : "=&d" (ctr) | ||
| 176 | : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo) | ||
| 177 | ); | ||
| 178 | } | ||
| 179 | |||
| 180 | SREG=sreg_prev; | ||
| 181 | } | ||
diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h new file mode 100755 index 000000000..54eef22d9 --- /dev/null +++ b/quantum/light_ws2812.h | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | /* | ||
| 2 | * light weight WS2812 lib include | ||
| 3 | * | ||
| 4 | * Version 2.3 - Nev 29th 2015 | ||
| 5 | * Author: Tim (cpldcpu@gmail.com) | ||
| 6 | * | ||
| 7 | * Please do not change this file! All configuration is handled in "ws2812_config.h" | ||
| 8 | * | ||
| 9 | * License: GNU GPL v2 (see License.txt) | ||
| 10 | + | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef LIGHT_WS2812_H_ | ||
| 14 | #define LIGHT_WS2812_H_ | ||
| 15 | |||
| 16 | #include <avr/io.h> | ||
| 17 | #include <avr/interrupt.h> | ||
| 18 | //#include "ws2812_config.h" | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Structure of the LED array | ||
| 22 | * | ||
| 23 | * cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106 | ||
| 24 | * cRGBW: RGBW for SK6812RGBW | ||
| 25 | */ | ||
| 26 | |||
| 27 | struct cRGB { uint8_t g; uint8_t r; uint8_t b; }; | ||
| 28 | struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;}; | ||
| 29 | |||
| 30 | |||
| 31 | |||
| 32 | /* User Interface | ||
| 33 | * | ||
| 34 | * Input: | ||
| 35 | * ledarray: An array of GRB data describing the LED colors | ||
| 36 | * number_of_leds: The number of LEDs to write | ||
| 37 | * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0) | ||
| 38 | * | ||
| 39 | * The functions will perform the following actions: | ||
| 40 | * - Set the data-out pin as output | ||
| 41 | * - Send out the LED data | ||
| 42 | * - Wait 50�s to reset the LEDs | ||
| 43 | */ | ||
| 44 | |||
| 45 | void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds); | ||
| 46 | void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask); | ||
| 47 | void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds); | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Old interface / Internal functions | ||
| 51 | * | ||
| 52 | * The functions take a byte-array and send to the data output as WS2812 bitstream. | ||
| 53 | * The length is the number of bytes to send - three per LED. | ||
| 54 | */ | ||
| 55 | |||
| 56 | void ws2812_sendarray (uint8_t *array,uint16_t length); | ||
| 57 | void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask); | ||
| 58 | |||
| 59 | |||
| 60 | /* | ||
| 61 | * Internal defines | ||
| 62 | */ | ||
| 63 | #ifndef CONCAT | ||
| 64 | #define CONCAT(a, b) a ## b | ||
| 65 | #endif | ||
| 66 | #ifndef CONCAT_EXP | ||
| 67 | #define CONCAT_EXP(a, b) CONCAT(a, b) | ||
| 68 | #endif | ||
| 69 | |||
| 70 | // #define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port) | ||
| 71 | // #define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port) | ||
| 72 | |||
| 73 | #endif /* LIGHT_WS2812_H_ */ | ||
diff --git a/quantum/matrix.c b/quantum/matrix.c new file mode 100644 index 000000000..094917025 --- /dev/null +++ b/quantum/matrix.c | |||
| @@ -0,0 +1,307 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2012 Jun Wako | ||
| 3 | Copyright 2014 Jack Humbert | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation, either version 2 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #include <stdint.h> | ||
| 19 | #include <stdbool.h> | ||
| 20 | #if defined(__AVR__) | ||
| 21 | #include <avr/io.h> | ||
| 22 | #endif | ||
| 23 | #include "wait.h" | ||
| 24 | #include "print.h" | ||
| 25 | #include "debug.h" | ||
| 26 | #include "util.h" | ||
| 27 | #include "matrix.h" | ||
| 28 | |||
| 29 | /* Set 0 if debouncing isn't needed */ | ||
| 30 | /* | ||
| 31 | * This constant define not debouncing time in msecs, but amount of matrix | ||
| 32 | * scan loops which should be made to get stable debounced results. | ||
| 33 | * | ||
| 34 | * On Ergodox matrix scan rate is relatively low, because of slow I2C. | ||
| 35 | * Now it's only 317 scans/second, or about 3.15 msec/scan. | ||
| 36 | * According to Cherry specs, debouncing time is 5 msec. | ||
| 37 | * | ||
| 38 | * And so, there is no sense to have DEBOUNCE higher than 2. | ||
| 39 | */ | ||
| 40 | |||
| 41 | #ifndef DEBOUNCING_DELAY | ||
| 42 | # define DEBOUNCING_DELAY 5 | ||
| 43 | #endif | ||
| 44 | static uint8_t debouncing = DEBOUNCING_DELAY; | ||
| 45 | |||
| 46 | static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; | ||
| 47 | static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; | ||
| 48 | |||
| 49 | /* matrix state(1:on, 0:off) */ | ||
| 50 | static matrix_row_t matrix[MATRIX_ROWS]; | ||
| 51 | static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | ||
| 52 | |||
| 53 | #if DIODE_DIRECTION == ROW2COL | ||
| 54 | static matrix_row_t matrix_reversed[MATRIX_COLS]; | ||
| 55 | static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS]; | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #if MATRIX_COLS > 16 | ||
| 59 | #define SHIFTER 1UL | ||
| 60 | #else | ||
| 61 | #define SHIFTER 1 | ||
| 62 | #endif | ||
| 63 | |||
| 64 | static matrix_row_t read_cols(void); | ||
| 65 | static void init_cols(void); | ||
| 66 | static void unselect_rows(void); | ||
| 67 | static void select_row(uint8_t row); | ||
| 68 | |||
| 69 | __attribute__ ((weak)) | ||
| 70 | void matrix_init_quantum(void) { | ||
| 71 | matrix_init_kb(); | ||
| 72 | } | ||
| 73 | |||
| 74 | __attribute__ ((weak)) | ||
| 75 | void matrix_scan_quantum(void) { | ||
| 76 | matrix_scan_kb(); | ||
| 77 | } | ||
| 78 | |||
| 79 | __attribute__ ((weak)) | ||
| 80 | void matrix_init_kb(void) { | ||
| 81 | matrix_init_user(); | ||
| 82 | } | ||
| 83 | |||
| 84 | __attribute__ ((weak)) | ||
| 85 | void matrix_scan_kb(void) { | ||
| 86 | matrix_scan_user(); | ||
| 87 | } | ||
| 88 | |||
| 89 | __attribute__ ((weak)) | ||
| 90 | void matrix_init_user(void) { | ||
| 91 | } | ||
| 92 | |||
| 93 | __attribute__ ((weak)) | ||
| 94 | void matrix_scan_user(void) { | ||
| 95 | } | ||
| 96 | |||
| 97 | inline | ||
| 98 | uint8_t matrix_rows(void) { | ||
| 99 | return MATRIX_ROWS; | ||
| 100 | } | ||
| 101 | |||
| 102 | inline | ||
| 103 | uint8_t matrix_cols(void) { | ||
| 104 | return MATRIX_COLS; | ||
| 105 | } | ||
| 106 | |||
| 107 | // void matrix_power_up(void) { | ||
| 108 | // #if DIODE_DIRECTION == COL2ROW | ||
| 109 | // for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { | ||
| 110 | // /* DDRxn */ | ||
| 111 | // _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF); | ||
| 112 | // toggle_row(r); | ||
| 113 | // } | ||
| 114 | // for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { | ||
| 115 | // /* PORTxn */ | ||
| 116 | // _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF); | ||
| 117 | // } | ||
| 118 | // #else | ||
| 119 | // for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { | ||
| 120 | // /* DDRxn */ | ||
| 121 | // _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF); | ||
| 122 | // toggle_col(c); | ||
| 123 | // } | ||
| 124 | // for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { | ||
| 125 | // /* PORTxn */ | ||
| 126 | // _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF); | ||
| 127 | // } | ||
| 128 | // #endif | ||
| 129 | // } | ||
| 130 | |||
| 131 | void matrix_init(void) { | ||
| 132 | // To use PORTF disable JTAG with writing JTD bit twice within four cycles. | ||
| 133 | #ifdef __AVR_ATmega32U4__ | ||
| 134 | MCUCR |= _BV(JTD); | ||
| 135 | MCUCR |= _BV(JTD); | ||
| 136 | #endif | ||
| 137 | |||
| 138 | // initialize row and col | ||
| 139 | unselect_rows(); | ||
| 140 | init_cols(); | ||
| 141 | |||
| 142 | // initialize matrix state: all keys off | ||
| 143 | for (uint8_t i=0; i < MATRIX_ROWS; i++) { | ||
| 144 | matrix[i] = 0; | ||
| 145 | matrix_debouncing[i] = 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | matrix_init_quantum(); | ||
| 149 | } | ||
| 150 | |||
| 151 | uint8_t matrix_scan(void) | ||
| 152 | { | ||
| 153 | |||
| 154 | #if DIODE_DIRECTION == COL2ROW | ||
| 155 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||
| 156 | select_row(i); | ||
| 157 | wait_us(30); // without this wait read unstable value. | ||
| 158 | matrix_row_t cols = read_cols(); | ||
| 159 | if (matrix_debouncing[i] != cols) { | ||
| 160 | matrix_debouncing[i] = cols; | ||
| 161 | if (debouncing) { | ||
| 162 | debug("bounce!: "); debug_hex(debouncing); debug("\n"); | ||
| 163 | } | ||
| 164 | debouncing = DEBOUNCING_DELAY; | ||
| 165 | } | ||
| 166 | unselect_rows(); | ||
| 167 | } | ||
| 168 | |||
| 169 | if (debouncing) { | ||
| 170 | if (--debouncing) { | ||
| 171 | wait_us(1); | ||
| 172 | } else { | ||
| 173 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||
| 174 | matrix[i] = matrix_debouncing[i]; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } | ||
| 178 | #else | ||
| 179 | for (uint8_t i = 0; i < MATRIX_COLS; i++) { | ||
| 180 | select_row(i); | ||
| 181 | wait_us(30); // without this wait read unstable value. | ||
| 182 | matrix_row_t rows = read_cols(); | ||
| 183 | if (matrix_reversed_debouncing[i] != rows) { | ||
| 184 | matrix_reversed_debouncing[i] = rows; | ||
| 185 | if (debouncing) { | ||
| 186 | debug("bounce!: "); debug_hex(debouncing); debug("\n"); | ||
| 187 | } | ||
| 188 | debouncing = DEBOUNCING_DELAY; | ||
| 189 | } | ||
| 190 | unselect_rows(); | ||
| 191 | } | ||
| 192 | |||
| 193 | if (debouncing) { | ||
| 194 | if (--debouncing) { | ||
| 195 | wait_us(1); | ||
| 196 | } else { | ||
| 197 | for (uint8_t i = 0; i < MATRIX_COLS; i++) { | ||
| 198 | matrix_reversed[i] = matrix_reversed_debouncing[i]; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | for (uint8_t y = 0; y < MATRIX_ROWS; y++) { | ||
| 203 | matrix_row_t row = 0; | ||
| 204 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { | ||
| 205 | row |= ((matrix_reversed[x] & (1<<y)) >> y) << x; | ||
| 206 | } | ||
| 207 | matrix[y] = row; | ||
| 208 | } | ||
| 209 | #endif | ||
| 210 | |||
| 211 | matrix_scan_quantum(); | ||
| 212 | |||
| 213 | return 1; | ||
| 214 | } | ||
| 215 | |||
| 216 | bool matrix_is_modified(void) | ||
| 217 | { | ||
| 218 | if (debouncing) return false; | ||
| 219 | return true; | ||
| 220 | } | ||
| 221 | |||
| 222 | inline | ||
| 223 | bool matrix_is_on(uint8_t row, uint8_t col) | ||
| 224 | { | ||
| 225 | return (matrix[row] & ((matrix_row_t)1<col)); | ||
| 226 | } | ||
| 227 | |||
| 228 | inline | ||
| 229 | matrix_row_t matrix_get_row(uint8_t row) | ||
| 230 | { | ||
| 231 | return matrix[row]; | ||
| 232 | } | ||
| 233 | |||
| 234 | void matrix_print(void) | ||
| 235 | { | ||
| 236 | print("\nr/c 0123456789ABCDEF\n"); | ||
| 237 | for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | ||
| 238 | phex(row); print(": "); | ||
| 239 | pbin_reverse16(matrix_get_row(row)); | ||
| 240 | print("\n"); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | uint8_t matrix_key_count(void) | ||
| 245 | { | ||
| 246 | uint8_t count = 0; | ||
| 247 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||
| 248 | count += bitpop16(matrix[i]); | ||
| 249 | } | ||
| 250 | return count; | ||
| 251 | } | ||
| 252 | |||
| 253 | static void init_cols(void) | ||
| 254 | { | ||
| 255 | #if DIODE_DIRECTION == COL2ROW | ||
| 256 | for(int x = 0; x < MATRIX_COLS; x++) { | ||
| 257 | int pin = col_pins[x]; | ||
| 258 | #else | ||
| 259 | for(int x = 0; x < MATRIX_ROWS; x++) { | ||
| 260 | int pin = row_pins[x]; | ||
| 261 | #endif | ||
| 262 | _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); | ||
| 263 | _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | static matrix_row_t read_cols(void) | ||
| 268 | { | ||
| 269 | matrix_row_t result = 0; | ||
| 270 | |||
| 271 | #if DIODE_DIRECTION == COL2ROW | ||
| 272 | for(int x = 0; x < MATRIX_COLS; x++) { | ||
| 273 | int pin = col_pins[x]; | ||
| 274 | #else | ||
| 275 | for(int x = 0; x < MATRIX_ROWS; x++) { | ||
| 276 | int pin = row_pins[x]; | ||
| 277 | #endif | ||
| 278 | result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x); | ||
| 279 | } | ||
| 280 | return result; | ||
| 281 | } | ||
| 282 | |||
| 283 | static void unselect_rows(void) | ||
| 284 | { | ||
| 285 | #if DIODE_DIRECTION == COL2ROW | ||
| 286 | for(int x = 0; x < MATRIX_ROWS; x++) { | ||
| 287 | int pin = row_pins[x]; | ||
| 288 | #else | ||
| 289 | for(int x = 0; x < MATRIX_COLS; x++) { | ||
| 290 | int pin = col_pins[x]; | ||
| 291 | #endif | ||
| 292 | _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); | ||
| 293 | _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | static void select_row(uint8_t row) | ||
| 298 | { | ||
| 299 | |||
| 300 | #if DIODE_DIRECTION == COL2ROW | ||
| 301 | int pin = row_pins[row]; | ||
| 302 | #else | ||
| 303 | int pin = col_pins[row]; | ||
| 304 | #endif | ||
| 305 | _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); | ||
| 306 | _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); | ||
| 307 | } | ||
diff --git a/quantum/process_keycode/process_chording.c b/quantum/process_keycode/process_chording.c new file mode 100644 index 000000000..d7814629f --- /dev/null +++ b/quantum/process_keycode/process_chording.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include "process_chording.h" | ||
| 2 | |||
| 3 | bool keys_chord(uint8_t keys[]) { | ||
| 4 | uint8_t keys_size = sizeof(keys)/sizeof(keys[0]); | ||
| 5 | bool pass = true; | ||
| 6 | uint8_t in = 0; | ||
| 7 | for (uint8_t i = 0; i < chord_key_count; i++) { | ||
| 8 | bool found = false; | ||
| 9 | for (uint8_t j = 0; j < keys_size; j++) { | ||
| 10 | if (chord_keys[i] == (keys[j] & 0xFF)) { | ||
| 11 | in++; // detects key in chord | ||
| 12 | found = true; | ||
| 13 | break; | ||
| 14 | } | ||
| 15 | } | ||
| 16 | if (found) | ||
| 17 | continue; | ||
| 18 | if (chord_keys[i] != 0) { | ||
| 19 | pass = false; // makes sure rest are blank | ||
| 20 | } | ||
| 21 | } | ||
| 22 | return (pass && (in == keys_size)); | ||
| 23 | } | ||
| 24 | |||
| 25 | bool process_chording(uint16_t keycode, keyrecord_t *record) { | ||
| 26 | if (keycode >= QK_CHORDING && keycode <= QK_CHORDING_MAX) { | ||
| 27 | if (record->event.pressed) { | ||
| 28 | if (!chording) { | ||
| 29 | chording = true; | ||
| 30 | for (uint8_t i = 0; i < CHORDING_MAX; i++) | ||
| 31 | chord_keys[i] = 0; | ||
| 32 | chord_key_count = 0; | ||
| 33 | chord_key_down = 0; | ||
| 34 | } | ||
| 35 | chord_keys[chord_key_count] = (keycode & 0xFF); | ||
| 36 | chord_key_count++; | ||
| 37 | chord_key_down++; | ||
| 38 | return false; | ||
| 39 | } else { | ||
| 40 | if (chording) { | ||
| 41 | chord_key_down--; | ||
| 42 | if (chord_key_down == 0) { | ||
| 43 | chording = false; | ||
| 44 | // Chord Dictionary | ||
| 45 | if (keys_chord((uint8_t[]){KC_ENTER, KC_SPACE})) { | ||
| 46 | register_code(KC_A); | ||
| 47 | unregister_code(KC_A); | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | for (uint8_t i = 0; i < chord_key_count; i++) { | ||
| 51 | register_code(chord_keys[i]); | ||
| 52 | unregister_code(chord_keys[i]); | ||
| 53 | return false; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | return true; | ||
| 60 | } \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_chording.h b/quantum/process_keycode/process_chording.h new file mode 100644 index 000000000..49c97db3b --- /dev/null +++ b/quantum/process_keycode/process_chording.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef PROCESS_CHORDING_H | ||
| 2 | #define PROCESS_CHORDING_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | // Chording stuff | ||
| 7 | #define CHORDING_MAX 4 | ||
| 8 | bool chording = false; | ||
| 9 | |||
| 10 | uint8_t chord_keys[CHORDING_MAX] = {0}; | ||
| 11 | uint8_t chord_key_count = 0; | ||
| 12 | uint8_t chord_key_down = 0; | ||
| 13 | |||
| 14 | bool process_chording(uint16_t keycode, keyrecord_t *record); | ||
| 15 | |||
| 16 | #endif \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c new file mode 100644 index 000000000..e53d221e7 --- /dev/null +++ b/quantum/process_keycode/process_leader.c | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #include "process_leader.h" | ||
| 2 | |||
| 3 | __attribute__ ((weak)) | ||
| 4 | void leader_start(void) {} | ||
| 5 | |||
| 6 | __attribute__ ((weak)) | ||
| 7 | void leader_end(void) {} | ||
| 8 | |||
| 9 | // Leader key stuff | ||
| 10 | bool leading = false; | ||
| 11 | uint16_t leader_time = 0; | ||
| 12 | |||
| 13 | uint16_t leader_sequence[5] = {0, 0, 0, 0, 0}; | ||
| 14 | uint8_t leader_sequence_size = 0; | ||
| 15 | |||
| 16 | bool process_leader(uint16_t keycode, keyrecord_t *record) { | ||
| 17 | // Leader key set-up | ||
| 18 | if (record->event.pressed) { | ||
| 19 | if (!leading && keycode == KC_LEAD) { | ||
| 20 | leader_start(); | ||
| 21 | leading = true; | ||
| 22 | leader_time = timer_read(); | ||
| 23 | leader_sequence_size = 0; | ||
| 24 | leader_sequence[0] = 0; | ||
| 25 | leader_sequence[1] = 0; | ||
| 26 | leader_sequence[2] = 0; | ||
| 27 | leader_sequence[3] = 0; | ||
| 28 | leader_sequence[4] = 0; | ||
| 29 | return false; | ||
| 30 | } | ||
| 31 | if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) { | ||
| 32 | leader_sequence[leader_sequence_size] = keycode; | ||
| 33 | leader_sequence_size++; | ||
| 34 | return false; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | return true; | ||
| 38 | } \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_leader.h b/quantum/process_keycode/process_leader.h new file mode 100644 index 000000000..c83db8abb --- /dev/null +++ b/quantum/process_keycode/process_leader.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #ifndef PROCESS_LEADER_H | ||
| 2 | #define PROCESS_LEADER_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | bool process_leader(uint16_t keycode, keyrecord_t *record); | ||
| 7 | |||
| 8 | void leader_start(void); | ||
| 9 | void leader_end(void); | ||
| 10 | |||
| 11 | #ifndef LEADER_TIMEOUT | ||
| 12 | #define LEADER_TIMEOUT 200 | ||
| 13 | #endif | ||
| 14 | #define SEQ_ONE_KEY(key) if (leader_sequence[0] == (key) && leader_sequence[1] == 0 && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0) | ||
| 15 | #define SEQ_TWO_KEYS(key1, key2) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0) | ||
| 16 | #define SEQ_THREE_KEYS(key1, key2, key3) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3) && leader_sequence[3] == 0 && leader_sequence[4] == 0) | ||
| 17 | #define SEQ_FOUR_KEYS(key1, key2, key3, key4) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3) && leader_sequence[3] == (key4) && leader_sequence[4] == 0) | ||
| 18 | #define SEQ_FIVE_KEYS(key1, key2, key3, key4, key5) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3) && leader_sequence[3] == (key4) && leader_sequence[4] == (key5)) | ||
| 19 | |||
| 20 | #define LEADER_EXTERNS() extern bool leading; extern uint16_t leader_time; extern uint16_t leader_sequence[5]; extern uint8_t leader_sequence_size | ||
| 21 | #define LEADER_DICTIONARY() if (leading && timer_elapsed(leader_time) > LEADER_TIMEOUT) | ||
| 22 | |||
| 23 | #endif \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c new file mode 100644 index 000000000..d6ab9c626 --- /dev/null +++ b/quantum/process_keycode/process_midi.c | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | #include "process_midi.h" | ||
| 2 | |||
| 3 | bool midi_activated = false; | ||
| 4 | uint8_t starting_note = 0x0C; | ||
| 5 | int offset = 7; | ||
| 6 | |||
| 7 | bool process_midi(uint16_t keycode, keyrecord_t *record) { | ||
| 8 | if (keycode == MI_ON && record->event.pressed) { | ||
| 9 | midi_activated = true; | ||
| 10 | music_scale_user(); | ||
| 11 | return false; | ||
| 12 | } | ||
| 13 | |||
| 14 | if (keycode == MI_OFF && record->event.pressed) { | ||
| 15 | midi_activated = false; | ||
| 16 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 17 | return false; | ||
| 18 | } | ||
| 19 | |||
| 20 | if (midi_activated) { | ||
| 21 | if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) { | ||
| 22 | if (record->event.pressed) { | ||
| 23 | starting_note++; // Change key | ||
| 24 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 25 | } | ||
| 26 | return false; | ||
| 27 | } | ||
| 28 | if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) { | ||
| 29 | if (record->event.pressed) { | ||
| 30 | starting_note--; // Change key | ||
| 31 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 32 | } | ||
| 33 | return false; | ||
| 34 | } | ||
| 35 | if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { | ||
| 36 | offset++; // Change scale | ||
| 37 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 38 | return false; | ||
| 39 | } | ||
| 40 | if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { | ||
| 41 | offset--; // Change scale | ||
| 42 | midi_send_cc(&midi_device, 0, 0x7B, 0); | ||
| 43 | return false; | ||
| 44 | } | ||
| 45 | // basic | ||
| 46 | // uint8_t note = (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row); | ||
| 47 | // advanced | ||
| 48 | // uint8_t note = (starting_note + record->event.key.col + offset)+12*(MATRIX_ROWS - record->event.key.row); | ||
| 49 | // guitar | ||
| 50 | uint8_t note = (starting_note + record->event.key.col + offset)+5*(MATRIX_ROWS - record->event.key.row); | ||
| 51 | // violin | ||
| 52 | // uint8_t note = (starting_note + record->event.key.col + offset)+7*(MATRIX_ROWS - record->event.key.row); | ||
| 53 | |||
| 54 | if (record->event.pressed) { | ||
| 55 | // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127); | ||
| 56 | midi_send_noteon(&midi_device, 0, note, 127); | ||
| 57 | } else { | ||
| 58 | // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127); | ||
| 59 | midi_send_noteoff(&midi_device, 0, note, 127); | ||
| 60 | } | ||
| 61 | |||
| 62 | if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through | ||
| 63 | return false; | ||
| 64 | } | ||
| 65 | return true; | ||
| 66 | } \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_midi.h b/quantum/process_keycode/process_midi.h new file mode 100644 index 000000000..acd4fc1b1 --- /dev/null +++ b/quantum/process_keycode/process_midi.h | |||
| @@ -0,0 +1,207 @@ | |||
| 1 | #ifndef PROCESS_MIDI_H | ||
| 2 | #define PROCESS_MIDI_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | bool process_midi(uint16_t keycode, keyrecord_t *record); | ||
| 7 | |||
| 8 | #define MIDI(n) ((n) | 0x6000) | ||
| 9 | #define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000 | ||
| 10 | |||
| 11 | #define CHNL(note, channel) (note + (channel << 8)) | ||
| 12 | |||
| 13 | #define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ | ||
| 14 | 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ | ||
| 15 | 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ | ||
| 16 | 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ | ||
| 17 | 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } | ||
| 18 | |||
| 19 | #define N_CN1 (0x600C + (12 * -1) + 0 ) | ||
| 20 | #define N_CN1S (0x600C + (12 * -1) + 1 ) | ||
| 21 | #define N_DN1F (0x600C + (12 * -1) + 1 ) | ||
| 22 | #define N_DN1 (0x600C + (12 * -1) + 2 ) | ||
| 23 | #define N_DN1S (0x600C + (12 * -1) + 3 ) | ||
| 24 | #define N_EN1F (0x600C + (12 * -1) + 3 ) | ||
| 25 | #define N_EN1 (0x600C + (12 * -1) + 4 ) | ||
| 26 | #define N_FN1 (0x600C + (12 * -1) + 5 ) | ||
| 27 | #define N_FN1S (0x600C + (12 * -1) + 6 ) | ||
| 28 | #define N_GN1F (0x600C + (12 * -1) + 6 ) | ||
| 29 | #define N_GN1 (0x600C + (12 * -1) + 7 ) | ||
| 30 | #define N_GN1S (0x600C + (12 * -1) + 8 ) | ||
| 31 | #define N_AN1F (0x600C + (12 * -1) + 8 ) | ||
| 32 | #define N_AN1 (0x600C + (12 * -1) + 9 ) | ||
| 33 | #define N_AN1S (0x600C + (12 * -1) + 10) | ||
| 34 | #define N_BN1F (0x600C + (12 * -1) + 10) | ||
| 35 | #define N_BN1 (0x600C + (12 * -1) + 11) | ||
| 36 | #define N_C0 (0x600C + (12 * 0) + 0 ) | ||
| 37 | #define N_C0S (0x600C + (12 * 0) + 1 ) | ||
| 38 | #define N_D0F (0x600C + (12 * 0) + 1 ) | ||
| 39 | #define N_D0 (0x600C + (12 * 0) + 2 ) | ||
| 40 | #define N_D0S (0x600C + (12 * 0) + 3 ) | ||
| 41 | #define N_E0F (0x600C + (12 * 0) + 3 ) | ||
| 42 | #define N_E0 (0x600C + (12 * 0) + 4 ) | ||
| 43 | #define N_F0 (0x600C + (12 * 0) + 5 ) | ||
| 44 | #define N_F0S (0x600C + (12 * 0) + 6 ) | ||
| 45 | #define N_G0F (0x600C + (12 * 0) + 6 ) | ||
| 46 | #define N_G0 (0x600C + (12 * 0) + 7 ) | ||
| 47 | #define N_G0S (0x600C + (12 * 0) + 8 ) | ||
| 48 | #define N_A0F (0x600C + (12 * 0) + 8 ) | ||
| 49 | #define N_A0 (0x600C + (12 * 0) + 9 ) | ||
| 50 | #define N_A0S (0x600C + (12 * 0) + 10) | ||
| 51 | #define N_B0F (0x600C + (12 * 0) + 10) | ||
| 52 | #define N_B0 (0x600C + (12 * 0) + 11) | ||
| 53 | #define N_C1 (0x600C + (12 * 1) + 0 ) | ||
| 54 | #define N_C1S (0x600C + (12 * 1) + 1 ) | ||
| 55 | #define N_D1F (0x600C + (12 * 1) + 1 ) | ||
| 56 | #define N_D1 (0x600C + (12 * 1) + 2 ) | ||
| 57 | #define N_D1S (0x600C + (12 * 1) + 3 ) | ||
| 58 | #define N_E1F (0x600C + (12 * 1) + 3 ) | ||
| 59 | #define N_E1 (0x600C + (12 * 1) + 4 ) | ||
| 60 | #define N_F1 (0x600C + (12 * 1) + 5 ) | ||
| 61 | #define N_F1S (0x600C + (12 * 1) + 6 ) | ||
| 62 | #define N_G1F (0x600C + (12 * 1) + 6 ) | ||
| 63 | #define N_G1 (0x600C + (12 * 1) + 7 ) | ||
| 64 | #define N_G1S (0x600C + (12 * 1) + 8 ) | ||
| 65 | #define N_A1F (0x600C + (12 * 1) + 8 ) | ||
| 66 | #define N_A1 (0x600C + (12 * 1) + 9 ) | ||
| 67 | #define N_A1S (0x600C + (12 * 1) + 10) | ||
| 68 | #define N_B1F (0x600C + (12 * 1) + 10) | ||
| 69 | #define N_B1 (0x600C + (12 * 1) + 11) | ||
| 70 | #define N_C2 (0x600C + (12 * 2) + 0 ) | ||
| 71 | #define N_C2S (0x600C + (12 * 2) + 1 ) | ||
| 72 | #define N_D2F (0x600C + (12 * 2) + 1 ) | ||
| 73 | #define N_D2 (0x600C + (12 * 2) + 2 ) | ||
| 74 | #define N_D2S (0x600C + (12 * 2) + 3 ) | ||
| 75 | #define N_E2F (0x600C + (12 * 2) + 3 ) | ||
| 76 | #define N_E2 (0x600C + (12 * 2) + 4 ) | ||
| 77 | #define N_F2 (0x600C + (12 * 2) + 5 ) | ||
| 78 | #define N_F2S (0x600C + (12 * 2) + 6 ) | ||
| 79 | #define N_G2F (0x600C + (12 * 2) + 6 ) | ||
| 80 | #define N_G2 (0x600C + (12 * 2) + 7 ) | ||
| 81 | #define N_G2S (0x600C + (12 * 2) + 8 ) | ||
| 82 | #define N_A2F (0x600C + (12 * 2) + 8 ) | ||
| 83 | #define N_A2 (0x600C + (12 * 2) + 9 ) | ||
| 84 | #define N_A2S (0x600C + (12 * 2) + 10) | ||
| 85 | #define N_B2F (0x600C + (12 * 2) + 10) | ||
| 86 | #define N_B2 (0x600C + (12 * 2) + 11) | ||
| 87 | #define N_C3 (0x600C + (12 * 3) + 0 ) | ||
| 88 | #define N_C3S (0x600C + (12 * 3) + 1 ) | ||
| 89 | #define N_D3F (0x600C + (12 * 3) + 1 ) | ||
| 90 | #define N_D3 (0x600C + (12 * 3) + 2 ) | ||
| 91 | #define N_D3S (0x600C + (12 * 3) + 3 ) | ||
| 92 | #define N_E3F (0x600C + (12 * 3) + 3 ) | ||
| 93 | #define N_E3 (0x600C + (12 * 3) + 4 ) | ||
| 94 | #define N_F3 (0x600C + (12 * 3) + 5 ) | ||
| 95 | #define N_F3S (0x600C + (12 * 3) + 6 ) | ||
| 96 | #define N_G3F (0x600C + (12 * 3) + 6 ) | ||
| 97 | #define N_G3 (0x600C + (12 * 3) + 7 ) | ||
| 98 | #define N_G3S (0x600C + (12 * 3) + 8 ) | ||
| 99 | #define N_A3F (0x600C + (12 * 3) + 8 ) | ||
| 100 | #define N_A3 (0x600C + (12 * 3) + 9 ) | ||
| 101 | #define N_A3S (0x600C + (12 * 3) + 10) | ||
| 102 | #define N_B3F (0x600C + (12 * 3) + 10) | ||
| 103 | #define N_B3 (0x600C + (12 * 3) + 11) | ||
| 104 | #define N_C4 (0x600C + (12 * 4) + 0 ) | ||
| 105 | #define N_C4S (0x600C + (12 * 4) + 1 ) | ||
| 106 | #define N_D4F (0x600C + (12 * 4) + 1 ) | ||
| 107 | #define N_D4 (0x600C + (12 * 4) + 2 ) | ||
| 108 | #define N_D4S (0x600C + (12 * 4) + 3 ) | ||
| 109 | #define N_E4F (0x600C + (12 * 4) + 3 ) | ||
| 110 | #define N_E4 (0x600C + (12 * 4) + 4 ) | ||
| 111 | #define N_F4 (0x600C + (12 * 4) + 5 ) | ||
| 112 | #define N_F4S (0x600C + (12 * 4) + 6 ) | ||
| 113 | #define N_G4F (0x600C + (12 * 4) + 6 ) | ||
| 114 | #define N_G4 (0x600C + (12 * 4) + 7 ) | ||
| 115 | #define N_G4S (0x600C + (12 * 4) + 8 ) | ||
| 116 | #define N_A4F (0x600C + (12 * 4) + 8 ) | ||
| 117 | #define N_A4 (0x600C + (12 * 4) + 9 ) | ||
| 118 | #define N_A4S (0x600C + (12 * 4) + 10) | ||
| 119 | #define N_B4F (0x600C + (12 * 4) + 10) | ||
| 120 | #define N_B4 (0x600C + (12 * 4) + 11) | ||
| 121 | #define N_C5 (0x600C + (12 * 5) + 0 ) | ||
| 122 | #define N_C5S (0x600C + (12 * 5) + 1 ) | ||
| 123 | #define N_D5F (0x600C + (12 * 5) + 1 ) | ||
| 124 | #define N_D5 (0x600C + (12 * 5) + 2 ) | ||
| 125 | #define N_D5S (0x600C + (12 * 5) + 3 ) | ||
| 126 | #define N_E5F (0x600C + (12 * 5) + 3 ) | ||
| 127 | #define N_E5 (0x600C + (12 * 5) + 4 ) | ||
| 128 | #define N_F5 (0x600C + (12 * 5) + 5 ) | ||
| 129 | #define N_F5S (0x600C + (12 * 5) + 6 ) | ||
| 130 | #define N_G5F (0x600C + (12 * 5) + 6 ) | ||
| 131 | #define N_G5 (0x600C + (12 * 5) + 7 ) | ||
| 132 | #define N_G5S (0x600C + (12 * 5) + 8 ) | ||
| 133 | #define N_A5F (0x600C + (12 * 5) + 8 ) | ||
| 134 | #define N_A5 (0x600C + (12 * 5) + 9 ) | ||
| 135 | #define N_A5S (0x600C + (12 * 5) + 10) | ||
| 136 | #define N_B5F (0x600C + (12 * 5) + 10) | ||
| 137 | #define N_B5 (0x600C + (12 * 5) + 11) | ||
| 138 | #define N_C6 (0x600C + (12 * 6) + 0 ) | ||
| 139 | #define N_C6S (0x600C + (12 * 6) + 1 ) | ||
| 140 | #define N_D6F (0x600C + (12 * 6) + 1 ) | ||
| 141 | #define N_D6 (0x600C + (12 * 6) + 2 ) | ||
| 142 | #define N_D6S (0x600C + (12 * 6) + 3 ) | ||
| 143 | #define N_E6F (0x600C + (12 * 6) + 3 ) | ||
| 144 | #define N_E6 (0x600C + (12 * 6) + 4 ) | ||
| 145 | #define N_F6 (0x600C + (12 * 6) + 5 ) | ||
| 146 | #define N_F6S (0x600C + (12 * 6) + 6 ) | ||
| 147 | #define N_G6F (0x600C + (12 * 6) + 6 ) | ||
| 148 | #define N_G6 (0x600C + (12 * 6) + 7 ) | ||
| 149 | #define N_G6S (0x600C + (12 * 6) + 8 ) | ||
| 150 | #define N_A6F (0x600C + (12 * 6) + 8 ) | ||
| 151 | #define N_A6 (0x600C + (12 * 6) + 9 ) | ||
| 152 | #define N_A6S (0x600C + (12 * 6) + 10) | ||
| 153 | #define N_B6F (0x600C + (12 * 6) + 10) | ||
| 154 | #define N_B6 (0x600C + (12 * 6) + 11) | ||
| 155 | #define N_C7 (0x600C + (12 * 7) + 0 ) | ||
| 156 | #define N_C7S (0x600C + (12 * 7) + 1 ) | ||
| 157 | #define N_D7F (0x600C + (12 * 7) + 1 ) | ||
| 158 | #define N_D7 (0x600C + (12 * 7) + 2 ) | ||
| 159 | #define N_D7S (0x600C + (12 * 7) + 3 ) | ||
| 160 | #define N_E7F (0x600C + (12 * 7) + 3 ) | ||
| 161 | #define N_E7 (0x600C + (12 * 7) + 4 ) | ||
| 162 | #define N_F7 (0x600C + (12 * 7) + 5 ) | ||
| 163 | #define N_F7S (0x600C + (12 * 7) + 6 ) | ||
| 164 | #define N_G7F (0x600C + (12 * 7) + 6 ) | ||
| 165 | #define N_G7 (0x600C + (12 * 7) + 7 ) | ||
| 166 | #define N_G7S (0x600C + (12 * 7) + 8 ) | ||
| 167 | #define N_A7F (0x600C + (12 * 7) + 8 ) | ||
| 168 | #define N_A7 (0x600C + (12 * 7) + 9 ) | ||
| 169 | #define N_A7S (0x600C + (12 * 7) + 10) | ||
| 170 | #define N_B7F (0x600C + (12 * 7) + 10) | ||
| 171 | #define N_B7 (0x600C + (12 * 7) + 11) | ||
| 172 | #define N_C8 (0x600C + (12 * 8) + 0 ) | ||
| 173 | #define N_C8S (0x600C + (12 * 8) + 1 ) | ||
| 174 | #define N_D8F (0x600C + (12 * 8) + 1 ) | ||
| 175 | #define N_D8 (0x600C + (12 * 8) + 2 ) | ||
| 176 | #define N_D8S (0x600C + (12 * 8) + 3 ) | ||
| 177 | #define N_E8F (0x600C + (12 * 8) + 3 ) | ||
| 178 | #define N_E8 (0x600C + (12 * 8) + 4 ) | ||
| 179 | #define N_F8 (0x600C + (12 * 8) + 5 ) | ||
| 180 | #define N_F8S (0x600C + (12 * 8) + 6 ) | ||
| 181 | #define N_G8F (0x600C + (12 * 8) + 6 ) | ||
| 182 | #define N_G8 (0x600C + (12 * 8) + 7 ) | ||
| 183 | #define N_G8S (0x600C + (12 * 8) + 8 ) | ||
| 184 | #define N_A8F (0x600C + (12 * 8) + 8 ) | ||
| 185 | #define N_A8 (0x600C + (12 * 8) + 9 ) | ||
| 186 | #define N_A8S (0x600C + (12 * 8) + 10) | ||
| 187 | #define N_B8F (0x600C + (12 * 8) + 10) | ||
| 188 | #define N_B8 (0x600C + (12 * 8) + 11) | ||
| 189 | #define N_C8 (0x600C + (12 * 8) + 0 ) | ||
| 190 | #define N_C8S (0x600C + (12 * 8) + 1 ) | ||
| 191 | #define N_D8F (0x600C + (12 * 8) + 1 ) | ||
| 192 | #define N_D8 (0x600C + (12 * 8) + 2 ) | ||
| 193 | #define N_D8S (0x600C + (12 * 8) + 3 ) | ||
| 194 | #define N_E8F (0x600C + (12 * 8) + 3 ) | ||
| 195 | #define N_E8 (0x600C + (12 * 8) + 4 ) | ||
| 196 | #define N_F8 (0x600C + (12 * 8) + 5 ) | ||
| 197 | #define N_F8S (0x600C + (12 * 8) + 6 ) | ||
| 198 | #define N_G8F (0x600C + (12 * 8) + 6 ) | ||
| 199 | #define N_G8 (0x600C + (12 * 8) + 7 ) | ||
| 200 | #define N_G8S (0x600C + (12 * 8) + 8 ) | ||
| 201 | #define N_A8F (0x600C + (12 * 8) + 8 ) | ||
| 202 | #define N_A8 (0x600C + (12 * 8) + 9 ) | ||
| 203 | #define N_A8S (0x600C + (12 * 8) + 10) | ||
| 204 | #define N_B8F (0x600C + (12 * 8) + 10) | ||
| 205 | #define N_B8 (0x600C + (12 * 8) + 11) | ||
| 206 | |||
| 207 | #endif \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c new file mode 100644 index 000000000..c8f3ddb90 --- /dev/null +++ b/quantum/process_keycode/process_music.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | #include "process_music.h" | ||
| 2 | |||
| 3 | bool music_activated = false; | ||
| 4 | uint8_t starting_note = 0x0C; | ||
| 5 | int offset = 7; | ||
| 6 | |||
| 7 | // music sequencer | ||
| 8 | static bool music_sequence_recording = false; | ||
| 9 | static bool music_sequence_playing = false; | ||
| 10 | static float music_sequence[16] = {0}; | ||
| 11 | static uint8_t music_sequence_count = 0; | ||
| 12 | static uint8_t music_sequence_position = 0; | ||
| 13 | |||
| 14 | static uint16_t music_sequence_timer = 0; | ||
| 15 | static uint16_t music_sequence_interval = 100; | ||
| 16 | |||
| 17 | bool process_music(uint16_t keycode, keyrecord_t *record) { | ||
| 18 | |||
| 19 | if (keycode == AU_ON && record->event.pressed) { | ||
| 20 | audio_on(); | ||
| 21 | return false; | ||
| 22 | } | ||
| 23 | |||
| 24 | if (keycode == AU_OFF && record->event.pressed) { | ||
| 25 | audio_off(); | ||
| 26 | return false; | ||
| 27 | } | ||
| 28 | |||
| 29 | if (keycode == AU_TOG && record->event.pressed) { | ||
| 30 | if (is_audio_on()) | ||
| 31 | { | ||
| 32 | audio_off(); | ||
| 33 | } | ||
| 34 | else | ||
| 35 | { | ||
| 36 | audio_on(); | ||
| 37 | } | ||
| 38 | return false; | ||
| 39 | } | ||
| 40 | |||
| 41 | if (keycode == MU_ON && record->event.pressed) { | ||
| 42 | music_on(); | ||
| 43 | return false; | ||
| 44 | } | ||
| 45 | |||
| 46 | if (keycode == MU_OFF && record->event.pressed) { | ||
| 47 | music_off(); | ||
| 48 | return false; | ||
| 49 | } | ||
| 50 | |||
| 51 | if (keycode == MU_TOG && record->event.pressed) { | ||
| 52 | if (music_activated) | ||
| 53 | { | ||
| 54 | music_off(); | ||
| 55 | } | ||
| 56 | else | ||
| 57 | { | ||
| 58 | music_on(); | ||
| 59 | } | ||
| 60 | return false; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (keycode == MUV_IN && record->event.pressed) { | ||
| 64 | voice_iterate(); | ||
| 65 | music_scale_user(); | ||
| 66 | return false; | ||
| 67 | } | ||
| 68 | |||
| 69 | if (keycode == MUV_DE && record->event.pressed) { | ||
| 70 | voice_deiterate(); | ||
| 71 | music_scale_user(); | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 75 | if (music_activated) { | ||
| 76 | |||
| 77 | if (keycode == KC_LCTL && record->event.pressed) { // Start recording | ||
| 78 | stop_all_notes(); | ||
| 79 | music_sequence_recording = true; | ||
| 80 | music_sequence_playing = false; | ||
| 81 | music_sequence_count = 0; | ||
| 82 | return false; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing | ||
| 86 | stop_all_notes(); | ||
| 87 | music_sequence_recording = false; | ||
| 88 | music_sequence_playing = false; | ||
| 89 | return false; | ||
| 90 | } | ||
| 91 | |||
| 92 | if (keycode == KC_LGUI && record->event.pressed) { // Start playing | ||
| 93 | stop_all_notes(); | ||
| 94 | music_sequence_recording = false; | ||
| 95 | music_sequence_playing = true; | ||
| 96 | music_sequence_position = 0; | ||
| 97 | music_sequence_timer = 0; | ||
| 98 | return false; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (keycode == KC_UP) { | ||
| 102 | if (record->event.pressed) | ||
| 103 | music_sequence_interval-=10; | ||
| 104 | return false; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (keycode == KC_DOWN) { | ||
| 108 | if (record->event.pressed) | ||
| 109 | music_sequence_interval+=10; | ||
| 110 | return false; | ||
| 111 | } | ||
| 112 | |||
| 113 | float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)); | ||
| 114 | if (record->event.pressed) { | ||
| 115 | play_note(freq, 0xF); | ||
| 116 | if (music_sequence_recording) { | ||
| 117 | music_sequence[music_sequence_count] = freq; | ||
| 118 | music_sequence_count++; | ||
| 119 | } | ||
| 120 | } else { | ||
| 121 | stop_note(freq); | ||
| 122 | } | ||
| 123 | |||
| 124 | if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through | ||
| 125 | return false; | ||
| 126 | } | ||
| 127 | return true; | ||
| 128 | } | ||
| 129 | |||
| 130 | bool is_music_on(void) { | ||
| 131 | return (music_activated != 0); | ||
| 132 | } | ||
| 133 | |||
| 134 | void music_toggle(void) { | ||
| 135 | if (!music_activated) { | ||
| 136 | music_on(); | ||
| 137 | } else { | ||
| 138 | music_off(); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | void music_on(void) { | ||
| 143 | music_activated = 1; | ||
| 144 | music_on_user(); | ||
| 145 | } | ||
| 146 | |||
| 147 | void music_off(void) { | ||
| 148 | music_activated = 0; | ||
| 149 | stop_all_notes(); | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | __attribute__ ((weak)) | ||
| 154 | void music_on_user() {} | ||
| 155 | |||
| 156 | __attribute__ ((weak)) | ||
| 157 | void audio_on_user() {} | ||
| 158 | |||
| 159 | __attribute__ ((weak)) | ||
| 160 | void music_scale_user() {} | ||
| 161 | |||
| 162 | void matrix_scan_music(void) { | ||
| 163 | if (music_sequence_playing) { | ||
| 164 | if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) { | ||
| 165 | music_sequence_timer = timer_read(); | ||
| 166 | stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]); | ||
| 167 | play_note(music_sequence[music_sequence_position], 0xF); | ||
| 168 | music_sequence_position = (music_sequence_position + 1) % music_sequence_count; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h new file mode 100644 index 000000000..318b3e387 --- /dev/null +++ b/quantum/process_keycode/process_music.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #ifndef PROCESS_MUSIC_H | ||
| 2 | #define PROCESS_MUSIC_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | bool process_music(uint16_t keycode, keyrecord_t *record); | ||
| 7 | |||
| 8 | bool is_music_on(void); | ||
| 9 | void music_toggle(void); | ||
| 10 | void music_on(void); | ||
| 11 | void music_off(void); | ||
| 12 | |||
| 13 | void audio_on_user(void); | ||
| 14 | void music_on_user(void); | ||
| 15 | void music_scale_user(void); | ||
| 16 | |||
| 17 | void matrix_scan_music(void); | ||
| 18 | |||
| 19 | #ifndef SCALE | ||
| 20 | #define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ | ||
| 21 | 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ | ||
| 22 | 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ | ||
| 23 | 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ | ||
| 24 | 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #endif \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c new file mode 100644 index 000000000..9b172e1b6 --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.c | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | #include "quantum.h" | ||
| 2 | |||
| 3 | static qk_tap_dance_state_t qk_tap_dance_state; | ||
| 4 | |||
| 5 | static void _process_tap_dance_action_pair (qk_tap_dance_state_t *state, | ||
| 6 | uint16_t kc1, uint16_t kc2) { | ||
| 7 | uint16_t kc; | ||
| 8 | |||
| 9 | if (state->count == 0) | ||
| 10 | return; | ||
| 11 | |||
| 12 | kc = (state->count == 1) ? kc1 : kc2; | ||
| 13 | |||
| 14 | register_code (kc); | ||
| 15 | unregister_code (kc); | ||
| 16 | |||
| 17 | if (state->count >= 2) { | ||
| 18 | reset_tap_dance (state); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | static void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, | ||
| 23 | qk_tap_dance_user_fn_t fn) | ||
| 24 | { | ||
| 25 | fn(state); | ||
| 26 | } | ||
| 27 | |||
| 28 | void process_tap_dance_action (uint16_t keycode) | ||
| 29 | { | ||
| 30 | uint16_t idx = keycode - QK_TAP_DANCE; | ||
| 31 | qk_tap_dance_action_t action; | ||
| 32 | |||
| 33 | action = tap_dance_actions[idx]; | ||
| 34 | |||
| 35 | switch (action.type) { | ||
| 36 | case QK_TAP_DANCE_TYPE_PAIR: | ||
| 37 | _process_tap_dance_action_pair (&qk_tap_dance_state, | ||
| 38 | action.pair.kc1, action.pair.kc2); | ||
| 39 | break; | ||
| 40 | case QK_TAP_DANCE_TYPE_FN: | ||
| 41 | _process_tap_dance_action_fn (&qk_tap_dance_state, action.fn); | ||
| 42 | break; | ||
| 43 | |||
| 44 | default: | ||
| 45 | break; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { | ||
| 50 | bool r = true; | ||
| 51 | |||
| 52 | switch(keycode) { | ||
| 53 | case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: | ||
| 54 | if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) { | ||
| 55 | process_tap_dance_action (qk_tap_dance_state.keycode); | ||
| 56 | } else { | ||
| 57 | r = false; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (record->event.pressed) { | ||
| 61 | qk_tap_dance_state.keycode = keycode; | ||
| 62 | qk_tap_dance_state.timer = timer_read (); | ||
| 63 | qk_tap_dance_state.count++; | ||
| 64 | } | ||
| 65 | break; | ||
| 66 | |||
| 67 | default: | ||
| 68 | if (qk_tap_dance_state.keycode) { | ||
| 69 | process_tap_dance_action (qk_tap_dance_state.keycode); | ||
| 70 | |||
| 71 | reset_tap_dance (&qk_tap_dance_state); | ||
| 72 | } | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | |||
| 76 | return r; | ||
| 77 | } | ||
| 78 | |||
| 79 | void matrix_scan_tap_dance () { | ||
| 80 | if (qk_tap_dance_state.keycode && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) { | ||
| 81 | process_tap_dance_action (qk_tap_dance_state.keycode); | ||
| 82 | |||
| 83 | reset_tap_dance (&qk_tap_dance_state); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void reset_tap_dance (qk_tap_dance_state_t *state) { | ||
| 88 | state->keycode = 0; | ||
| 89 | state->count = 0; | ||
| 90 | } | ||
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h new file mode 100644 index 000000000..b9d7c7fcf --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | #ifndef PROCESS_TAP_DANCE_H | ||
| 2 | #define PROCESS_TAP_DANCE_H | ||
| 3 | |||
| 4 | #ifdef TAP_DANCE_ENABLE | ||
| 5 | |||
| 6 | #include <stdbool.h> | ||
| 7 | #include <inttypes.h> | ||
| 8 | |||
| 9 | typedef struct | ||
| 10 | { | ||
| 11 | uint8_t count; | ||
| 12 | uint16_t keycode; | ||
| 13 | uint16_t timer; | ||
| 14 | } qk_tap_dance_state_t; | ||
| 15 | |||
| 16 | #define TD(n) (QK_TAP_DANCE + n) | ||
| 17 | |||
| 18 | typedef enum | ||
| 19 | { | ||
| 20 | QK_TAP_DANCE_TYPE_PAIR, | ||
| 21 | QK_TAP_DANCE_TYPE_FN, | ||
| 22 | } qk_tap_dance_type_t; | ||
| 23 | |||
| 24 | typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state); | ||
| 25 | |||
| 26 | typedef struct | ||
| 27 | { | ||
| 28 | qk_tap_dance_type_t type; | ||
| 29 | union { | ||
| 30 | struct { | ||
| 31 | uint16_t kc1; | ||
| 32 | uint16_t kc2; | ||
| 33 | } pair; | ||
| 34 | qk_tap_dance_user_fn_t fn; | ||
| 35 | }; | ||
| 36 | } qk_tap_dance_action_t; | ||
| 37 | |||
| 38 | #define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \ | ||
| 39 | .type = QK_TAP_DANCE_TYPE_PAIR, \ | ||
| 40 | .pair = { kc1, kc2 } \ | ||
| 41 | } | ||
| 42 | |||
| 43 | #define ACTION_TAP_DANCE_FN(user_fn) { \ | ||
| 44 | .type = QK_TAP_DANCE_TYPE_FN, \ | ||
| 45 | .fn = user_fn \ | ||
| 46 | } | ||
| 47 | |||
| 48 | extern const qk_tap_dance_action_t tap_dance_actions[]; | ||
| 49 | |||
| 50 | /* To be used internally */ | ||
| 51 | |||
| 52 | bool process_tap_dance(uint16_t keycode, keyrecord_t *record); | ||
| 53 | void matrix_scan_tap_dance (void); | ||
| 54 | void reset_tap_dance (qk_tap_dance_state_t *state); | ||
| 55 | |||
| 56 | #else | ||
| 57 | |||
| 58 | #define TD(n) KC_NO | ||
| 59 | |||
| 60 | #endif | ||
| 61 | |||
| 62 | #endif | ||
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c new file mode 100644 index 000000000..ad5d7f86b --- /dev/null +++ b/quantum/process_keycode/process_unicode.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #include "process_unicode.h" | ||
| 2 | |||
| 3 | static uint8_t input_mode; | ||
| 4 | |||
| 5 | uint16_t hex_to_keycode(uint8_t hex) | ||
| 6 | { | ||
| 7 | if (hex == 0x0) { | ||
| 8 | return KC_0; | ||
| 9 | } else if (hex < 0xA) { | ||
| 10 | return KC_1 + (hex - 0x1); | ||
| 11 | } else { | ||
| 12 | return KC_A + (hex - 0xA); | ||
| 13 | } | ||
| 14 | } | ||
| 15 | |||
| 16 | void set_unicode_mode(uint8_t os_target) | ||
| 17 | { | ||
| 18 | input_mode = os_target; | ||
| 19 | } | ||
| 20 | |||
| 21 | bool process_unicode(uint16_t keycode, keyrecord_t *record) { | ||
| 22 | if (keycode > QK_UNICODE && record->event.pressed) { | ||
| 23 | uint16_t unicode = keycode & 0x7FFF; | ||
| 24 | switch(input_mode) { | ||
| 25 | case UC_OSX: | ||
| 26 | register_code(KC_LALT); | ||
| 27 | break; | ||
| 28 | case UC_LNX: | ||
| 29 | register_code(KC_LCTL); | ||
| 30 | register_code(KC_LSFT); | ||
| 31 | register_code(KC_U); | ||
| 32 | unregister_code(KC_U); | ||
| 33 | break; | ||
| 34 | case UC_WIN: | ||
| 35 | register_code(KC_LALT); | ||
| 36 | register_code(KC_PPLS); | ||
| 37 | unregister_code(KC_PPLS); | ||
| 38 | break; | ||
| 39 | } | ||
| 40 | for(int i = 3; i >= 0; i--) { | ||
| 41 | uint8_t digit = ((unicode >> (i*4)) & 0xF); | ||
| 42 | register_code(hex_to_keycode(digit)); | ||
| 43 | unregister_code(hex_to_keycode(digit)); | ||
| 44 | } | ||
| 45 | switch(input_mode) { | ||
| 46 | case UC_OSX: | ||
| 47 | case UC_WIN: | ||
| 48 | unregister_code(KC_LALT); | ||
| 49 | break; | ||
| 50 | case UC_LNX: | ||
| 51 | unregister_code(KC_LCTL); | ||
| 52 | unregister_code(KC_LSFT); | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | return true; | ||
| 57 | } \ No newline at end of file | ||
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h new file mode 100644 index 000000000..ca17f8f66 --- /dev/null +++ b/quantum/process_keycode/process_unicode.h | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | #ifndef PROCESS_UNICODE_H | ||
| 2 | #define PROCESS_UNICODE_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | #define UC_OSX 0 | ||
| 7 | #define UC_LNX 1 | ||
| 8 | #define UC_WIN 2 | ||
| 9 | #define UC_BSD 3 | ||
| 10 | |||
| 11 | void set_unicode_input_mode(uint8_t os_target); | ||
| 12 | |||
| 13 | bool process_unicode(uint16_t keycode, keyrecord_t *record); | ||
| 14 | |||
| 15 | #define UC_BSPC UC(0x0008) | ||
| 16 | |||
| 17 | #define UC_SPC UC(0x0020) | ||
| 18 | |||
| 19 | #define UC_EXLM UC(0x0021) | ||
| 20 | #define UC_DQUT UC(0x0022) | ||
| 21 | #define UC_HASH UC(0x0023) | ||
| 22 | #define UC_DLR UC(0x0024) | ||
| 23 | #define UC_PERC UC(0x0025) | ||
| 24 | #define UC_AMPR UC(0x0026) | ||
| 25 | #define UC_QUOT UC(0x0027) | ||
| 26 | #define UC_LPRN UC(0x0028) | ||
| 27 | #define UC_RPRN UC(0x0029) | ||
| 28 | #define UC_ASTR UC(0x002A) | ||
| 29 | #define UC_PLUS UC(0x002B) | ||
| 30 | #define UC_COMM UC(0x002C) | ||
| 31 | #define UC_DASH UC(0x002D) | ||
| 32 | #define UC_DOT UC(0x002E) | ||
| 33 | #define UC_SLSH UC(0x002F) | ||
| 34 | |||
| 35 | #define UC_0 UC(0x0030) | ||
| 36 | #define UC_1 UC(0x0031) | ||
| 37 | #define UC_2 UC(0x0032) | ||
| 38 | #define UC_3 UC(0x0033) | ||
| 39 | #define UC_4 UC(0x0034) | ||
| 40 | #define UC_5 UC(0x0035) | ||
| 41 | #define UC_6 UC(0x0036) | ||
| 42 | #define UC_7 UC(0x0037) | ||
| 43 | #define UC_8 UC(0x0038) | ||
| 44 | #define UC_9 UC(0x0039) | ||
| 45 | |||
| 46 | #define UC_COLN UC(0x003A) | ||
| 47 | #define UC_SCLN UC(0x003B) | ||
| 48 | #define UC_LT UC(0x003C) | ||
| 49 | #define UC_EQL UC(0x003D) | ||
| 50 | #define UC_GT UC(0x003E) | ||
| 51 | #define UC_QUES UC(0x003F) | ||
| 52 | #define UC_AT UC(0x0040) | ||
| 53 | |||
| 54 | #define UC_A UC(0x0041) | ||
| 55 | #define UC_B UC(0x0042) | ||
| 56 | #define UC_C UC(0x0043) | ||
| 57 | #define UC_D UC(0x0044) | ||
| 58 | #define UC_E UC(0x0045) | ||
| 59 | #define UC_F UC(0x0046) | ||
| 60 | #define UC_G UC(0x0047) | ||
| 61 | #define UC_H UC(0x0048) | ||
| 62 | #define UC_I UC(0x0049) | ||
| 63 | #define UC_J UC(0x004A) | ||
| 64 | #define UC_K UC(0x004B) | ||
| 65 | #define UC_L UC(0x004C) | ||
| 66 | #define UC_M UC(0x004D) | ||
| 67 | #define UC_N UC(0x004E) | ||
| 68 | #define UC_O UC(0x004F) | ||
| 69 | #define UC_P UC(0x0050) | ||
| 70 | #define UC_Q UC(0x0051) | ||
| 71 | #define UC_R UC(0x0052) | ||
| 72 | #define UC_S UC(0x0053) | ||
| 73 | #define UC_T UC(0x0054) | ||
| 74 | #define UC_U UC(0x0055) | ||
| 75 | #define UC_V UC(0x0056) | ||
| 76 | #define UC_W UC(0x0057) | ||
| 77 | #define UC_X UC(0x0058) | ||
| 78 | #define UC_Y UC(0x0059) | ||
| 79 | #define UC_Z UC(0x005A) | ||
| 80 | |||
| 81 | #define UC_LBRC UC(0x005B) | ||
| 82 | #define UC_BSLS UC(0x005C) | ||
| 83 | #define UC_RBRC UC(0x005D) | ||
| 84 | #define UC_CIRM UC(0x005E) | ||
| 85 | #define UC_UNDR UC(0x005F) | ||
| 86 | |||
| 87 | #define UC_GRV UC(0x0060) | ||
| 88 | |||
| 89 | #define UC_a UC(0x0061) | ||
| 90 | #define UC_b UC(0x0062) | ||
| 91 | #define UC_c UC(0x0063) | ||
| 92 | #define UC_d UC(0x0064) | ||
| 93 | #define UC_e UC(0x0065) | ||
| 94 | #define UC_f UC(0x0066) | ||
| 95 | #define UC_g UC(0x0067) | ||
| 96 | #define UC_h UC(0x0068) | ||
| 97 | #define UC_i UC(0x0069) | ||
| 98 | #define UC_j UC(0x006A) | ||
| 99 | #define UC_k UC(0x006B) | ||
| 100 | #define UC_l UC(0x006C) | ||
| 101 | #define UC_m UC(0x006D) | ||
| 102 | #define UC_n UC(0x006E) | ||
| 103 | #define UC_o UC(0x006F) | ||
| 104 | #define UC_p UC(0x0070) | ||
| 105 | #define UC_q UC(0x0071) | ||
| 106 | #define UC_r UC(0x0072) | ||
| 107 | #define UC_s UC(0x0073) | ||
| 108 | #define UC_t UC(0x0074) | ||
| 109 | #define UC_u UC(0x0075) | ||
| 110 | #define UC_v UC(0x0076) | ||
| 111 | #define UC_w UC(0x0077) | ||
| 112 | #define UC_x UC(0x0078) | ||
| 113 | #define UC_y UC(0x0079) | ||
| 114 | #define UC_z UC(0x007A) | ||
| 115 | |||
| 116 | #define UC_LCBR UC(0x007B) | ||
| 117 | #define UC_PIPE UC(0x007C) | ||
| 118 | #define UC_RCBR UC(0x007D) | ||
| 119 | #define UC_TILD UC(0x007E) | ||
| 120 | #define UC_DEL UC(0x007F) | ||
| 121 | |||
| 122 | #endif \ No newline at end of file | ||
diff --git a/quantum/quantum.c b/quantum/quantum.c new file mode 100644 index 000000000..d59bd5a3f --- /dev/null +++ b/quantum/quantum.c | |||
| @@ -0,0 +1,717 @@ | |||
| 1 | #include "quantum.h" | ||
| 2 | |||
| 3 | __attribute__ ((weak)) | ||
| 4 | bool process_action_kb(keyrecord_t *record) { | ||
| 5 | return true; | ||
| 6 | } | ||
| 7 | |||
| 8 | __attribute__ ((weak)) | ||
| 9 | bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | ||
| 10 | return process_record_user(keycode, record); | ||
| 11 | } | ||
| 12 | |||
| 13 | __attribute__ ((weak)) | ||
| 14 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
| 15 | return true; | ||
| 16 | } | ||
| 17 | |||
| 18 | // Shift / paren setup | ||
| 19 | |||
| 20 | #ifndef LSPO_KEY | ||
| 21 | #define LSPO_KEY KC_9 | ||
| 22 | #endif | ||
| 23 | #ifndef RSPC_KEY | ||
| 24 | #define RSPC_KEY KC_0 | ||
| 25 | #endif | ||
| 26 | |||
| 27 | static bool shift_interrupted[2] = {0, 0}; | ||
| 28 | |||
| 29 | bool process_record_quantum(keyrecord_t *record) { | ||
| 30 | |||
| 31 | /* This gets the keycode from the key pressed */ | ||
| 32 | keypos_t key = record->event.key; | ||
| 33 | uint16_t keycode; | ||
| 34 | |||
| 35 | #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) | ||
| 36 | uint8_t layer; | ||
| 37 | |||
| 38 | if (record->event.pressed) { | ||
| 39 | layer = layer_switch_get_layer(key); | ||
| 40 | update_source_layers_cache(key, layer); | ||
| 41 | } else { | ||
| 42 | layer = read_source_layers_cache(key); | ||
| 43 | } | ||
| 44 | keycode = keymap_key_to_keycode(layer, key); | ||
| 45 | #else | ||
| 46 | keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key); | ||
| 47 | #endif | ||
| 48 | |||
| 49 | // This is how you use actions here | ||
| 50 | // if (keycode == KC_LEAD) { | ||
| 51 | // action_t action; | ||
| 52 | // action.code = ACTION_DEFAULT_LAYER_SET(0); | ||
| 53 | // process_action(record, action); | ||
| 54 | // return false; | ||
| 55 | // } | ||
| 56 | |||
| 57 | if (!( | ||
| 58 | process_record_kb(keycode, record) && | ||
| 59 | #ifdef MIDI_ENABLE | ||
| 60 | process_midi(keycode, record) && | ||
| 61 | #endif | ||
| 62 | #ifdef AUDIO_ENABLE | ||
| 63 | process_music(keycode, record) && | ||
| 64 | #endif | ||
| 65 | #ifdef TAP_DANCE_ENABLE | ||
| 66 | process_tap_dance(keycode, record) && | ||
| 67 | #endif | ||
| 68 | #ifndef DISABLE_LEADER | ||
| 69 | process_leader(keycode, record) && | ||
| 70 | #endif | ||
| 71 | #ifndef DISABLE_CHORDING | ||
| 72 | process_chording(keycode, record) && | ||
| 73 | #endif | ||
| 74 | #ifdef UNICODE_ENABLE | ||
| 75 | process_unicode(keycode, record) && | ||
| 76 | #endif | ||
| 77 | true)) { | ||
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 81 | // Shift / paren setup | ||
| 82 | |||
| 83 | switch(keycode) { | ||
| 84 | case RESET: | ||
| 85 | if (record->event.pressed) { | ||
| 86 | clear_keyboard(); | ||
| 87 | #ifdef AUDIO_ENABLE | ||
| 88 | stop_all_notes(); | ||
| 89 | shutdown_user(); | ||
| 90 | #endif | ||
| 91 | wait_ms(250); | ||
| 92 | #ifdef ATREUS_ASTAR | ||
| 93 | *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific | ||
| 94 | #endif | ||
| 95 | bootloader_jump(); | ||
| 96 | return false; | ||
| 97 | } | ||
| 98 | break; | ||
| 99 | case DEBUG: | ||
| 100 | if (record->event.pressed) { | ||
| 101 | print("\nDEBUG: enabled.\n"); | ||
| 102 | debug_enable = true; | ||
| 103 | return false; | ||
| 104 | } | ||
| 105 | break; | ||
| 106 | case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_UNSWAP_ALT_GUI: | ||
| 107 | if (record->event.pressed) { | ||
| 108 | // MAGIC actions (BOOTMAGIC without the boot) | ||
| 109 | if (!eeconfig_is_enabled()) { | ||
| 110 | eeconfig_init(); | ||
| 111 | } | ||
| 112 | /* keymap config */ | ||
| 113 | keymap_config.raw = eeconfig_read_keymap(); | ||
| 114 | if (keycode == MAGIC_SWAP_CONTROL_CAPSLOCK) { | ||
| 115 | keymap_config.swap_control_capslock = 1; | ||
| 116 | } else if (keycode == MAGIC_CAPSLOCK_TO_CONTROL) { | ||
| 117 | keymap_config.capslock_to_control = 1; | ||
| 118 | } else if (keycode == MAGIC_SWAP_LALT_LGUI) { | ||
| 119 | keymap_config.swap_lalt_lgui = 1; | ||
| 120 | } else if (keycode == MAGIC_SWAP_RALT_RGUI) { | ||
| 121 | keymap_config.swap_ralt_rgui = 1; | ||
| 122 | } else if (keycode == MAGIC_NO_GUI) { | ||
| 123 | keymap_config.no_gui = 1; | ||
| 124 | } else if (keycode == MAGIC_SWAP_GRAVE_ESC) { | ||
| 125 | keymap_config.swap_grave_esc = 1; | ||
| 126 | } else if (keycode == MAGIC_SWAP_BACKSLASH_BACKSPACE) { | ||
| 127 | keymap_config.swap_backslash_backspace = 1; | ||
| 128 | } else if (keycode == MAGIC_HOST_NKRO) { | ||
| 129 | keymap_config.nkro = 1; | ||
| 130 | } else if (keycode == MAGIC_SWAP_ALT_GUI) { | ||
| 131 | keymap_config.swap_lalt_lgui = 1; | ||
| 132 | keymap_config.swap_ralt_rgui = 1; | ||
| 133 | } | ||
| 134 | /* UNs */ | ||
| 135 | else if (keycode == MAGIC_UNSWAP_CONTROL_CAPSLOCK) { | ||
| 136 | keymap_config.swap_control_capslock = 0; | ||
| 137 | } else if (keycode == MAGIC_UNCAPSLOCK_TO_CONTROL) { | ||
| 138 | keymap_config.capslock_to_control = 0; | ||
| 139 | } else if (keycode == MAGIC_UNSWAP_LALT_LGUI) { | ||
| 140 | keymap_config.swap_lalt_lgui = 0; | ||
| 141 | } else if (keycode == MAGIC_UNSWAP_RALT_RGUI) { | ||
| 142 | keymap_config.swap_ralt_rgui = 0; | ||
| 143 | } else if (keycode == MAGIC_UNNO_GUI) { | ||
| 144 | keymap_config.no_gui = 0; | ||
| 145 | } else if (keycode == MAGIC_UNSWAP_GRAVE_ESC) { | ||
| 146 | keymap_config.swap_grave_esc = 0; | ||
| 147 | } else if (keycode == MAGIC_UNSWAP_BACKSLASH_BACKSPACE) { | ||
| 148 | keymap_config.swap_backslash_backspace = 0; | ||
| 149 | } else if (keycode == MAGIC_UNHOST_NKRO) { | ||
| 150 | keymap_config.nkro = 0; | ||
| 151 | } else if (keycode == MAGIC_UNSWAP_ALT_GUI) { | ||
| 152 | keymap_config.swap_lalt_lgui = 0; | ||
| 153 | keymap_config.swap_ralt_rgui = 0; | ||
| 154 | } | ||
| 155 | eeconfig_update_keymap(keymap_config.raw); | ||
| 156 | return false; | ||
| 157 | } | ||
| 158 | break; | ||
| 159 | case KC_LSPO: { | ||
| 160 | if (record->event.pressed) { | ||
| 161 | shift_interrupted[0] = false; | ||
| 162 | register_mods(MOD_BIT(KC_LSFT)); | ||
| 163 | } | ||
| 164 | else { | ||
| 165 | if (!shift_interrupted[0]) { | ||
| 166 | register_code(LSPO_KEY); | ||
| 167 | unregister_code(LSPO_KEY); | ||
| 168 | } | ||
| 169 | unregister_mods(MOD_BIT(KC_LSFT)); | ||
| 170 | } | ||
| 171 | return false; | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | |||
| 175 | case KC_RSPC: { | ||
| 176 | if (record->event.pressed) { | ||
| 177 | shift_interrupted[1] = false; | ||
| 178 | register_mods(MOD_BIT(KC_RSFT)); | ||
| 179 | } | ||
| 180 | else { | ||
| 181 | if (!shift_interrupted[1]) { | ||
| 182 | register_code(RSPC_KEY); | ||
| 183 | unregister_code(RSPC_KEY); | ||
| 184 | } | ||
| 185 | unregister_mods(MOD_BIT(KC_RSFT)); | ||
| 186 | } | ||
| 187 | return false; | ||
| 188 | break; | ||
| 189 | } | ||
| 190 | default: { | ||
| 191 | shift_interrupted[0] = true; | ||
| 192 | shift_interrupted[1] = true; | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | return process_action_kb(record); | ||
| 198 | } | ||
| 199 | |||
| 200 | const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = { | ||
| 201 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 202 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 203 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 204 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 205 | 0, 1, 1, 1, 1, 1, 1, 0, | ||
| 206 | 1, 1, 1, 1, 0, 0, 0, 0, | ||
| 207 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 208 | 0, 0, 1, 0, 1, 0, 1, 1, | ||
| 209 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 210 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 211 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 212 | 1, 1, 1, 0, 0, 0, 1, 1, | ||
| 213 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 214 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 215 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 216 | 0, 0, 0, 1, 1, 1, 1, 0 | ||
| 217 | }; | ||
| 218 | |||
| 219 | const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = { | ||
| 220 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 221 | KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, | ||
| 222 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 223 | 0, 0, 0, KC_ESC, 0, 0, 0, 0, | ||
| 224 | KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, | ||
| 225 | KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, | ||
| 226 | KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, | ||
| 227 | KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, | ||
| 228 | KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, | ||
| 229 | KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, | ||
| 230 | KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, | ||
| 231 | KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, | ||
| 232 | KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, | ||
| 233 | KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, | ||
| 234 | KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, | ||
| 235 | KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL | ||
| 236 | }; | ||
| 237 | |||
| 238 | /* for users whose OSes are set to Colemak */ | ||
| 239 | #if 0 | ||
| 240 | #include "keymap_colemak.h" | ||
| 241 | |||
| 242 | const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = { | ||
| 243 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 244 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 245 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 246 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 247 | 0, 1, 1, 1, 1, 1, 1, 0, | ||
| 248 | 1, 1, 1, 1, 0, 0, 0, 0, | ||
| 249 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 250 | 0, 0, 1, 0, 1, 0, 1, 1, | ||
| 251 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 252 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 253 | 1, 1, 1, 1, 1, 1, 1, 1, | ||
| 254 | 1, 1, 1, 0, 0, 0, 1, 1, | ||
| 255 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 256 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 257 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 258 | 0, 0, 0, 1, 1, 1, 1, 0 | ||
| 259 | }; | ||
| 260 | |||
| 261 | const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = { | ||
| 262 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 263 | KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, | ||
| 264 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 265 | 0, 0, 0, KC_ESC, 0, 0, 0, 0, | ||
| 266 | KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, | ||
| 267 | KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, | ||
| 268 | KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, | ||
| 269 | KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, | ||
| 270 | KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G, | ||
| 271 | CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O, | ||
| 272 | CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W, | ||
| 273 | CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, | ||
| 274 | KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G, | ||
| 275 | CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O, | ||
| 276 | CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W, | ||
| 277 | CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL | ||
| 278 | }; | ||
| 279 | |||
| 280 | #endif | ||
| 281 | |||
| 282 | void send_string(const char *str) { | ||
| 283 | while (1) { | ||
| 284 | uint8_t keycode; | ||
| 285 | uint8_t ascii_code = pgm_read_byte(str); | ||
| 286 | if (!ascii_code) break; | ||
| 287 | keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]); | ||
| 288 | if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) { | ||
| 289 | register_code(KC_LSFT); | ||
| 290 | register_code(keycode); | ||
| 291 | unregister_code(keycode); | ||
| 292 | unregister_code(KC_LSFT); | ||
| 293 | } | ||
| 294 | else { | ||
| 295 | register_code(keycode); | ||
| 296 | unregister_code(keycode); | ||
| 297 | } | ||
| 298 | ++str; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) { | ||
| 303 | if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) { | ||
| 304 | layer_on(layer3); | ||
| 305 | } else { | ||
| 306 | layer_off(layer3); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | void tap_random_base64(void) { | ||
| 311 | #if defined(__AVR_ATmega32U4__) | ||
| 312 | uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64; | ||
| 313 | #else | ||
| 314 | uint8_t key = rand() % 64; | ||
| 315 | #endif | ||
| 316 | switch (key) { | ||
| 317 | case 0 ... 25: | ||
| 318 | register_code(KC_LSFT); | ||
| 319 | register_code(key + KC_A); | ||
| 320 | unregister_code(key + KC_A); | ||
| 321 | unregister_code(KC_LSFT); | ||
| 322 | break; | ||
| 323 | case 26 ... 51: | ||
| 324 | register_code(key - 26 + KC_A); | ||
| 325 | unregister_code(key - 26 + KC_A); | ||
| 326 | break; | ||
| 327 | case 52: | ||
| 328 | register_code(KC_0); | ||
| 329 | unregister_code(KC_0); | ||
| 330 | break; | ||
| 331 | case 53 ... 61: | ||
| 332 | register_code(key - 53 + KC_1); | ||
| 333 | unregister_code(key - 53 + KC_1); | ||
| 334 | break; | ||
| 335 | case 62: | ||
| 336 | register_code(KC_LSFT); | ||
| 337 | register_code(KC_EQL); | ||
| 338 | unregister_code(KC_EQL); | ||
| 339 | unregister_code(KC_LSFT); | ||
| 340 | break; | ||
| 341 | case 63: | ||
| 342 | register_code(KC_SLSH); | ||
| 343 | unregister_code(KC_SLSH); | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | void matrix_init_quantum() { | ||
| 349 | #ifdef BACKLIGHT_ENABLE | ||
| 350 | backlight_init_ports(); | ||
| 351 | #endif | ||
| 352 | matrix_init_kb(); | ||
| 353 | } | ||
| 354 | |||
| 355 | void matrix_scan_quantum() { | ||
| 356 | #ifdef AUDIO_ENABLE | ||
| 357 | matrix_scan_music(); | ||
| 358 | #endif | ||
| 359 | |||
| 360 | #ifdef TAP_DANCE_ENABLE | ||
| 361 | matrix_scan_tap_dance(); | ||
| 362 | #endif | ||
| 363 | matrix_scan_kb(); | ||
| 364 | } | ||
| 365 | |||
| 366 | #if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN) | ||
| 367 | |||
| 368 | static const uint8_t backlight_pin = BACKLIGHT_PIN; | ||
| 369 | |||
| 370 | #if BACKLIGHT_PIN == B7 | ||
| 371 | # define COM1x1 COM1C1 | ||
| 372 | # define OCR1x OCR1C | ||
| 373 | #elif BACKLIGHT_PIN == B6 | ||
| 374 | # define COM1x1 COM1B1 | ||
| 375 | # define OCR1x OCR1B | ||
| 376 | #elif BACKLIGHT_PIN == B5 | ||
| 377 | # define COM1x1 COM1A1 | ||
| 378 | # define OCR1x OCR1A | ||
| 379 | #else | ||
| 380 | # error "Backlight pin not supported - use B5, B6, or B7" | ||
| 381 | #endif | ||
| 382 | |||
| 383 | __attribute__ ((weak)) | ||
| 384 | void backlight_init_ports(void) | ||
| 385 | { | ||
| 386 | |||
| 387 | // Setup backlight pin as output and output low. | ||
| 388 | // DDRx |= n | ||
| 389 | _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF); | ||
| 390 | // PORTx &= ~n | ||
| 391 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | ||
| 392 | |||
| 393 | // Use full 16-bit resolution. | ||
| 394 | ICR1 = 0xFFFF; | ||
| 395 | |||
| 396 | // I could write a wall of text here to explain... but TL;DW | ||
| 397 | // Go read the ATmega32u4 datasheet. | ||
| 398 | // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on | ||
| 399 | |||
| 400 | // Pin PB7 = OCR1C (Timer 1, Channel C) | ||
| 401 | // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 | ||
| 402 | // (i.e. start high, go low when counter matches.) | ||
| 403 | // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 | ||
| 404 | // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 | ||
| 405 | |||
| 406 | TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010; | ||
| 407 | TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; | ||
| 408 | |||
| 409 | backlight_init(); | ||
| 410 | #ifdef BACKLIGHT_BREATHING | ||
| 411 | breathing_defaults(); | ||
| 412 | #endif | ||
| 413 | } | ||
| 414 | |||
| 415 | __attribute__ ((weak)) | ||
| 416 | void backlight_set(uint8_t level) | ||
| 417 | { | ||
| 418 | // Prevent backlight blink on lowest level | ||
| 419 | // PORTx &= ~n | ||
| 420 | _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); | ||
| 421 | |||
| 422 | if ( level == 0 ) { | ||
| 423 | // Turn off PWM control on backlight pin, revert to output low. | ||
| 424 | TCCR1A &= ~(_BV(COM1x1)); | ||
| 425 | OCR1x = 0x0; | ||
| 426 | } else if ( level == BACKLIGHT_LEVELS ) { | ||
| 427 | // Turn on PWM control of backlight pin | ||
| 428 | TCCR1A |= _BV(COM1x1); | ||
| 429 | // Set the brightness | ||
| 430 | OCR1x = 0xFFFF; | ||
| 431 | } else { | ||
| 432 | // Turn on PWM control of backlight pin | ||
| 433 | TCCR1A |= _BV(COM1x1); | ||
| 434 | // Set the brightness | ||
| 435 | OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2)); | ||
| 436 | } | ||
| 437 | |||
| 438 | #ifdef BACKLIGHT_BREATHING | ||
| 439 | breathing_intensity_default(); | ||
| 440 | #endif | ||
| 441 | } | ||
| 442 | |||
| 443 | |||
| 444 | #ifdef BACKLIGHT_BREATHING | ||
| 445 | |||
| 446 | #define BREATHING_NO_HALT 0 | ||
| 447 | #define BREATHING_HALT_OFF 1 | ||
| 448 | #define BREATHING_HALT_ON 2 | ||
| 449 | |||
| 450 | static uint8_t breath_intensity; | ||
| 451 | static uint8_t breath_speed; | ||
| 452 | static uint16_t breathing_index; | ||
| 453 | static uint8_t breathing_halt; | ||
| 454 | |||
| 455 | void breathing_enable(void) | ||
| 456 | { | ||
| 457 | if (get_backlight_level() == 0) | ||
| 458 | { | ||
| 459 | breathing_index = 0; | ||
| 460 | } | ||
| 461 | else | ||
| 462 | { | ||
| 463 | // Set breathing_index to be at the midpoint (brightest point) | ||
| 464 | breathing_index = 0x20 << breath_speed; | ||
| 465 | } | ||
| 466 | |||
| 467 | breathing_halt = BREATHING_NO_HALT; | ||
| 468 | |||
| 469 | // Enable breathing interrupt | ||
| 470 | TIMSK1 |= _BV(OCIE1A); | ||
| 471 | } | ||
| 472 | |||
| 473 | void breathing_pulse(void) | ||
| 474 | { | ||
| 475 | if (get_backlight_level() == 0) | ||
| 476 | { | ||
| 477 | breathing_index = 0; | ||
| 478 | } | ||
| 479 | else | ||
| 480 | { | ||
| 481 | // Set breathing_index to be at the midpoint + 1 (brightest point) | ||
| 482 | breathing_index = 0x21 << breath_speed; | ||
| 483 | } | ||
| 484 | |||
| 485 | breathing_halt = BREATHING_HALT_ON; | ||
| 486 | |||
| 487 | // Enable breathing interrupt | ||
| 488 | TIMSK1 |= _BV(OCIE1A); | ||
| 489 | } | ||
| 490 | |||
| 491 | void breathing_disable(void) | ||
| 492 | { | ||
| 493 | // Disable breathing interrupt | ||
| 494 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 495 | backlight_set(get_backlight_level()); | ||
| 496 | } | ||
| 497 | |||
| 498 | void breathing_self_disable(void) | ||
| 499 | { | ||
| 500 | if (get_backlight_level() == 0) | ||
| 501 | { | ||
| 502 | breathing_halt = BREATHING_HALT_OFF; | ||
| 503 | } | ||
| 504 | else | ||
| 505 | { | ||
| 506 | breathing_halt = BREATHING_HALT_ON; | ||
| 507 | } | ||
| 508 | |||
| 509 | //backlight_set(get_backlight_level()); | ||
| 510 | } | ||
| 511 | |||
| 512 | void breathing_toggle(void) | ||
| 513 | { | ||
| 514 | if (!is_breathing()) | ||
| 515 | { | ||
| 516 | if (get_backlight_level() == 0) | ||
| 517 | { | ||
| 518 | breathing_index = 0; | ||
| 519 | } | ||
| 520 | else | ||
| 521 | { | ||
| 522 | // Set breathing_index to be at the midpoint + 1 (brightest point) | ||
| 523 | breathing_index = 0x21 << breath_speed; | ||
| 524 | } | ||
| 525 | |||
| 526 | breathing_halt = BREATHING_NO_HALT; | ||
| 527 | } | ||
| 528 | |||
| 529 | // Toggle breathing interrupt | ||
| 530 | TIMSK1 ^= _BV(OCIE1A); | ||
| 531 | |||
| 532 | // Restore backlight level | ||
| 533 | if (!is_breathing()) | ||
| 534 | { | ||
| 535 | backlight_set(get_backlight_level()); | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | bool is_breathing(void) | ||
| 540 | { | ||
| 541 | return (TIMSK1 && _BV(OCIE1A)); | ||
| 542 | } | ||
| 543 | |||
| 544 | void breathing_intensity_default(void) | ||
| 545 | { | ||
| 546 | //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS); | ||
| 547 | breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2)); | ||
| 548 | } | ||
| 549 | |||
| 550 | void breathing_intensity_set(uint8_t value) | ||
| 551 | { | ||
| 552 | breath_intensity = value; | ||
| 553 | } | ||
| 554 | |||
| 555 | void breathing_speed_default(void) | ||
| 556 | { | ||
| 557 | breath_speed = 4; | ||
| 558 | } | ||
| 559 | |||
| 560 | void breathing_speed_set(uint8_t value) | ||
| 561 | { | ||
| 562 | bool is_breathing_now = is_breathing(); | ||
| 563 | uint8_t old_breath_speed = breath_speed; | ||
| 564 | |||
| 565 | if (is_breathing_now) | ||
| 566 | { | ||
| 567 | // Disable breathing interrupt | ||
| 568 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 569 | } | ||
| 570 | |||
| 571 | breath_speed = value; | ||
| 572 | |||
| 573 | if (is_breathing_now) | ||
| 574 | { | ||
| 575 | // Adjust index to account for new speed | ||
| 576 | breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed; | ||
| 577 | |||
| 578 | // Enable breathing interrupt | ||
| 579 | TIMSK1 |= _BV(OCIE1A); | ||
| 580 | } | ||
| 581 | |||
| 582 | } | ||
| 583 | |||
| 584 | void breathing_speed_inc(uint8_t value) | ||
| 585 | { | ||
| 586 | if ((uint16_t)(breath_speed - value) > 10 ) | ||
| 587 | { | ||
| 588 | breathing_speed_set(0); | ||
| 589 | } | ||
| 590 | else | ||
| 591 | { | ||
| 592 | breathing_speed_set(breath_speed - value); | ||
| 593 | } | ||
| 594 | } | ||
| 595 | |||
| 596 | void breathing_speed_dec(uint8_t value) | ||
| 597 | { | ||
| 598 | if ((uint16_t)(breath_speed + value) > 10 ) | ||
| 599 | { | ||
| 600 | breathing_speed_set(10); | ||
| 601 | } | ||
| 602 | else | ||
| 603 | { | ||
| 604 | breathing_speed_set(breath_speed + value); | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | void breathing_defaults(void) | ||
| 609 | { | ||
| 610 | breathing_intensity_default(); | ||
| 611 | breathing_speed_default(); | ||
| 612 | breathing_halt = BREATHING_NO_HALT; | ||
| 613 | } | ||
| 614 | |||
| 615 | /* Breathing Sleep LED brighness(PWM On period) table | ||
| 616 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
| 617 | * | ||
| 618 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
| 619 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
| 620 | */ | ||
| 621 | static const uint8_t breathing_table[64] PROGMEM = { | ||
| 622 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, | ||
| 623 | 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, | ||
| 624 | 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, | ||
| 625 | 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 626 | }; | ||
| 627 | |||
| 628 | ISR(TIMER1_COMPA_vect) | ||
| 629 | { | ||
| 630 | // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity; | ||
| 631 | |||
| 632 | |||
| 633 | uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F; | ||
| 634 | |||
| 635 | if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F))) | ||
| 636 | { | ||
| 637 | // Disable breathing interrupt | ||
| 638 | TIMSK1 &= ~_BV(OCIE1A); | ||
| 639 | } | ||
| 640 | |||
| 641 | OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity; | ||
| 642 | |||
| 643 | } | ||
| 644 | |||
| 645 | |||
| 646 | |||
| 647 | #endif // breathing | ||
| 648 | |||
| 649 | #else // backlight | ||
| 650 | |||
| 651 | __attribute__ ((weak)) | ||
| 652 | void backlight_init_ports(void) | ||
| 653 | { | ||
| 654 | |||
| 655 | } | ||
| 656 | |||
| 657 | __attribute__ ((weak)) | ||
| 658 | void backlight_set(uint8_t level) | ||
| 659 | { | ||
| 660 | |||
| 661 | } | ||
| 662 | |||
| 663 | #endif // backlight | ||
| 664 | |||
| 665 | |||
| 666 | |||
| 667 | __attribute__ ((weak)) | ||
| 668 | void led_set_user(uint8_t usb_led) { | ||
| 669 | |||
| 670 | } | ||
| 671 | |||
| 672 | __attribute__ ((weak)) | ||
| 673 | void led_set_kb(uint8_t usb_led) { | ||
| 674 | led_set_user(usb_led); | ||
| 675 | } | ||
| 676 | |||
| 677 | __attribute__ ((weak)) | ||
| 678 | void led_init_ports(void) | ||
| 679 | { | ||
| 680 | |||
| 681 | } | ||
| 682 | |||
| 683 | __attribute__ ((weak)) | ||
| 684 | void led_set(uint8_t usb_led) | ||
| 685 | { | ||
| 686 | |||
| 687 | // Example LED Code | ||
| 688 | // | ||
| 689 | // // Using PE6 Caps Lock LED | ||
| 690 | // if (usb_led & (1<<USB_LED_CAPS_LOCK)) | ||
| 691 | // { | ||
| 692 | // // Output high. | ||
| 693 | // DDRE |= (1<<6); | ||
| 694 | // PORTE |= (1<<6); | ||
| 695 | // } | ||
| 696 | // else | ||
| 697 | // { | ||
| 698 | // // Output low. | ||
| 699 | // DDRE &= ~(1<<6); | ||
| 700 | // PORTE &= ~(1<<6); | ||
| 701 | // } | ||
| 702 | |||
| 703 | led_set_kb(usb_led); | ||
| 704 | } | ||
| 705 | |||
| 706 | |||
| 707 | //------------------------------------------------------------------------------ | ||
| 708 | // Override these functions in your keymap file to play different tunes on | ||
| 709 | // different events such as startup and bootloader jump | ||
| 710 | |||
| 711 | __attribute__ ((weak)) | ||
| 712 | void startup_user() {} | ||
| 713 | |||
| 714 | __attribute__ ((weak)) | ||
| 715 | void shutdown_user() {} | ||
| 716 | |||
| 717 | //------------------------------------------------------------------------------ | ||
diff --git a/quantum/quantum.h b/quantum/quantum.h new file mode 100644 index 000000000..3a0b74202 --- /dev/null +++ b/quantum/quantum.h | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | #ifndef QUANTUM_H | ||
| 2 | #define QUANTUM_H | ||
| 3 | |||
| 4 | #if defined(__AVR__) | ||
| 5 | #include <avr/pgmspace.h> | ||
| 6 | #include <avr/io.h> | ||
| 7 | #include <avr/interrupt.h> | ||
| 8 | #endif | ||
| 9 | #include "wait.h" | ||
| 10 | #include "matrix.h" | ||
| 11 | #include "keymap.h" | ||
| 12 | #ifdef BACKLIGHT_ENABLE | ||
| 13 | #include "backlight.h" | ||
| 14 | #endif | ||
| 15 | #ifdef RGBLIGHT_ENABLE | ||
| 16 | #include "rgblight.h" | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #include "action_layer.h" | ||
| 20 | #include "eeconfig.h" | ||
| 21 | #include <stddef.h> | ||
| 22 | #include "bootloader.h" | ||
| 23 | #include "timer.h" | ||
| 24 | #include "config_common.h" | ||
| 25 | #include "led.h" | ||
| 26 | #include "action_util.h" | ||
| 27 | #include <stdlib.h> | ||
| 28 | |||
| 29 | |||
| 30 | extern uint32_t default_layer_state; | ||
| 31 | |||
| 32 | #ifndef NO_ACTION_LAYER | ||
| 33 | extern uint32_t layer_state; | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #ifdef MIDI_ENABLE | ||
| 37 | #include <lufa.h> | ||
| 38 | #include "process_midi.h" | ||
| 39 | #endif | ||
| 40 | |||
| 41 | #ifdef AUDIO_ENABLE | ||
| 42 | #include "audio.h" | ||
| 43 | #include "process_music.h" | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifndef DISABLE_LEADER | ||
| 47 | #include "process_leader.h" | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #define DISABLE_CHORDING | ||
| 51 | #ifndef DISABLE_CHORDING | ||
| 52 | #include "process_chording.h" | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #ifdef UNICODE_ENABLE | ||
| 56 | #include "process_unicode.h" | ||
| 57 | #endif | ||
| 58 | |||
| 59 | #include "process_tap_dance.h" | ||
| 60 | |||
| 61 | #define SEND_STRING(str) send_string(PSTR(str)) | ||
| 62 | void send_string(const char *str); | ||
| 63 | |||
| 64 | // For tri-layer | ||
| 65 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); | ||
| 66 | |||
| 67 | void tap_random_base64(void); | ||
| 68 | |||
| 69 | #define IS_LAYER_ON(layer) (layer_state & (1UL << (layer))) | ||
| 70 | #define IS_LAYER_OFF(layer) (~layer_state & (1UL << (layer))) | ||
| 71 | |||
| 72 | void matrix_init_kb(void); | ||
| 73 | void matrix_scan_kb(void); | ||
| 74 | void matrix_init_user(void); | ||
| 75 | void matrix_scan_user(void); | ||
| 76 | bool process_action_kb(keyrecord_t *record); | ||
| 77 | bool process_record_kb(uint16_t keycode, keyrecord_t *record); | ||
| 78 | bool process_record_user(uint16_t keycode, keyrecord_t *record); | ||
| 79 | |||
| 80 | void startup_user(void); | ||
| 81 | void shutdown_user(void); | ||
| 82 | |||
| 83 | #ifdef BACKLIGHT_ENABLE | ||
| 84 | void backlight_init_ports(void); | ||
| 85 | |||
| 86 | #ifdef BACKLIGHT_BREATHING | ||
| 87 | void breathing_enable(void); | ||
| 88 | void breathing_pulse(void); | ||
| 89 | void breathing_disable(void); | ||
| 90 | void breathing_self_disable(void); | ||
| 91 | void breathing_toggle(void); | ||
| 92 | bool is_breathing(void); | ||
| 93 | |||
| 94 | void breathing_defaults(void); | ||
| 95 | void breathing_intensity_default(void); | ||
| 96 | void breathing_speed_default(void); | ||
| 97 | void breathing_speed_set(uint8_t value); | ||
| 98 | void breathing_speed_inc(uint8_t value); | ||
| 99 | void breathing_speed_dec(uint8_t value); | ||
| 100 | #endif | ||
| 101 | |||
| 102 | #endif | ||
| 103 | |||
| 104 | void led_set_user(uint8_t usb_led); | ||
| 105 | void led_set_kb(uint8_t usb_led); | ||
| 106 | |||
| 107 | #endif | ||
diff --git a/quantum/rgblight.c b/quantum/rgblight.c new file mode 100644 index 000000000..c29ffedc3 --- /dev/null +++ b/quantum/rgblight.c | |||
| @@ -0,0 +1,505 @@ | |||
| 1 | #include <avr/eeprom.h> | ||
| 2 | #include <avr/interrupt.h> | ||
| 3 | #include <util/delay.h> | ||
| 4 | #include "progmem.h" | ||
| 5 | #include "timer.h" | ||
| 6 | #include "rgblight.h" | ||
| 7 | #include "debug.h" | ||
| 8 | |||
| 9 | const uint8_t DIM_CURVE[] PROGMEM = { | ||
| 10 | 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, | ||
| 11 | 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, | ||
| 12 | 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, | ||
| 13 | 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, | ||
| 14 | 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, | ||
| 15 | 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, | ||
| 16 | 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, | ||
| 17 | 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, | ||
| 18 | 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, | ||
| 19 | 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, | ||
| 20 | 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, | ||
| 21 | 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, | ||
| 22 | 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, | ||
| 23 | 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, | ||
| 24 | 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, | ||
| 25 | 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, | ||
| 26 | }; | ||
| 27 | const uint8_t RGBLED_BREATHING_TABLE[] PROGMEM = {0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124,127,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0}; | ||
| 28 | const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; | ||
| 29 | const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; | ||
| 30 | const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
| 31 | const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
| 32 | const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
| 33 | |||
| 34 | rgblight_config_t rgblight_config; | ||
| 35 | rgblight_config_t inmem_config; | ||
| 36 | struct cRGB led[RGBLED_NUM]; | ||
| 37 | uint8_t rgblight_inited = 0; | ||
| 38 | |||
| 39 | |||
| 40 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) { | ||
| 41 | /* convert hue, saturation and brightness ( HSB/HSV ) to RGB | ||
| 42 | The DIM_CURVE is used only on brightness/value and on saturation (inverted). | ||
| 43 | This looks the most natural. | ||
| 44 | */ | ||
| 45 | uint8_t r = 0, g = 0, b = 0; | ||
| 46 | |||
| 47 | val = pgm_read_byte(&DIM_CURVE[val]); | ||
| 48 | sat = 255 - pgm_read_byte(&DIM_CURVE[255 - sat]); | ||
| 49 | |||
| 50 | uint8_t base; | ||
| 51 | |||
| 52 | if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. | ||
| 53 | r = val; | ||
| 54 | g = val; | ||
| 55 | b = val; | ||
| 56 | } else { | ||
| 57 | base = ((255 - sat) * val) >> 8; | ||
| 58 | |||
| 59 | switch (hue / 60) { | ||
| 60 | case 0: | ||
| 61 | r = val; | ||
| 62 | g = (((val - base)*hue) / 60) + base; | ||
| 63 | b = base; | ||
| 64 | break; | ||
| 65 | |||
| 66 | case 1: | ||
| 67 | r = (((val - base)*(60 - (hue % 60))) / 60) + base; | ||
| 68 | g = val; | ||
| 69 | b = base; | ||
| 70 | break; | ||
| 71 | |||
| 72 | case 2: | ||
| 73 | r = base; | ||
| 74 | g = val; | ||
| 75 | b = (((val - base)*(hue % 60)) / 60) + base; | ||
| 76 | break; | ||
| 77 | |||
| 78 | case 3: | ||
| 79 | r = base; | ||
| 80 | g = (((val - base)*(60 - (hue % 60))) / 60) + base; | ||
| 81 | b = val; | ||
| 82 | break; | ||
| 83 | |||
| 84 | case 4: | ||
| 85 | r = (((val - base)*(hue % 60)) / 60) + base; | ||
| 86 | g = base; | ||
| 87 | b = val; | ||
| 88 | break; | ||
| 89 | |||
| 90 | case 5: | ||
| 91 | r = val; | ||
| 92 | g = base; | ||
| 93 | b = (((val - base)*(60 - (hue % 60))) / 60) + base; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | setrgb(r,g,b, led1); | ||
| 98 | } | ||
| 99 | |||
| 100 | void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { | ||
| 101 | (*led1).r = r; | ||
| 102 | (*led1).g = g; | ||
| 103 | (*led1).b = b; | ||
| 104 | } | ||
| 105 | |||
| 106 | |||
| 107 | uint32_t eeconfig_read_rgblight(void) { | ||
| 108 | return eeprom_read_dword(EECONFIG_RGBLIGHT); | ||
| 109 | } | ||
| 110 | void eeconfig_update_rgblight(uint32_t val) { | ||
| 111 | eeprom_update_dword(EECONFIG_RGBLIGHT, val); | ||
| 112 | } | ||
| 113 | void eeconfig_update_rgblight_default(void) { | ||
| 114 | dprintf("eeconfig_update_rgblight_default\n"); | ||
| 115 | rgblight_config.enable = 1; | ||
| 116 | rgblight_config.mode = 1; | ||
| 117 | rgblight_config.hue = 200; | ||
| 118 | rgblight_config.sat = 204; | ||
| 119 | rgblight_config.val = 204; | ||
| 120 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 121 | } | ||
| 122 | void eeconfig_debug_rgblight(void) { | ||
| 123 | dprintf("rgblight_config eprom\n"); | ||
| 124 | dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); | ||
| 125 | dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); | ||
| 126 | dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); | ||
| 127 | dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); | ||
| 128 | dprintf("rgblight_config.val = %d\n", rgblight_config.val); | ||
| 129 | } | ||
| 130 | |||
| 131 | void rgblight_init(void) { | ||
| 132 | debug_enable = 1; // Debug ON! | ||
| 133 | dprintf("rgblight_init called.\n"); | ||
| 134 | rgblight_inited = 1; | ||
| 135 | dprintf("rgblight_init start!\n"); | ||
| 136 | if (!eeconfig_is_enabled()) { | ||
| 137 | dprintf("rgblight_init eeconfig is not enabled.\n"); | ||
| 138 | eeconfig_init(); | ||
| 139 | eeconfig_update_rgblight_default(); | ||
| 140 | } | ||
| 141 | rgblight_config.raw = eeconfig_read_rgblight(); | ||
| 142 | if (!rgblight_config.mode) { | ||
| 143 | dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); | ||
| 144 | eeconfig_update_rgblight_default(); | ||
| 145 | rgblight_config.raw = eeconfig_read_rgblight(); | ||
| 146 | } | ||
| 147 | eeconfig_debug_rgblight(); // display current eeprom values | ||
| 148 | |||
| 149 | rgblight_timer_init(); // setup the timer | ||
| 150 | |||
| 151 | if (rgblight_config.enable) { | ||
| 152 | rgblight_mode(rgblight_config.mode); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | void rgblight_increase(void) { | ||
| 157 | uint8_t mode = 0; | ||
| 158 | if (rgblight_config.mode < RGBLIGHT_MODES) { | ||
| 159 | mode = rgblight_config.mode + 1; | ||
| 160 | } | ||
| 161 | rgblight_mode(mode); | ||
| 162 | } | ||
| 163 | |||
| 164 | void rgblight_decrease(void) { | ||
| 165 | uint8_t mode = 0; | ||
| 166 | if (rgblight_config.mode > 1) { //mode will never < 1, if mode is less than 1, eeprom need to be initialized. | ||
| 167 | mode = rgblight_config.mode-1; | ||
| 168 | } | ||
| 169 | rgblight_mode(mode); | ||
| 170 | } | ||
| 171 | |||
| 172 | void rgblight_step(void) { | ||
| 173 | uint8_t mode = 0; | ||
| 174 | mode = rgblight_config.mode + 1; | ||
| 175 | if (mode > RGBLIGHT_MODES) { | ||
| 176 | mode = 1; | ||
| 177 | } | ||
| 178 | rgblight_mode(mode); | ||
| 179 | } | ||
| 180 | |||
| 181 | void rgblight_mode(uint8_t mode) { | ||
| 182 | if (!rgblight_config.enable) { | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | if (mode<1) { | ||
| 186 | rgblight_config.mode = 1; | ||
| 187 | } else if (mode > RGBLIGHT_MODES) { | ||
| 188 | rgblight_config.mode = RGBLIGHT_MODES; | ||
| 189 | } else { | ||
| 190 | rgblight_config.mode = mode; | ||
| 191 | } | ||
| 192 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 193 | xprintf("rgblight mode: %u\n", rgblight_config.mode); | ||
| 194 | if (rgblight_config.mode == 1) { | ||
| 195 | rgblight_timer_disable(); | ||
| 196 | } else if (rgblight_config.mode >=2 && rgblight_config.mode <=23) { | ||
| 197 | // MODE 2-5, breathing | ||
| 198 | // MODE 6-8, rainbow mood | ||
| 199 | // MODE 9-14, rainbow swirl | ||
| 200 | // MODE 15-20, snake | ||
| 201 | // MODE 21-23, knight | ||
| 202 | rgblight_timer_enable(); | ||
| 203 | } | ||
| 204 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | ||
| 205 | } | ||
| 206 | |||
| 207 | void rgblight_toggle(void) { | ||
| 208 | rgblight_config.enable ^= 1; | ||
| 209 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 210 | xprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable); | ||
| 211 | if (rgblight_config.enable) { | ||
| 212 | rgblight_mode(rgblight_config.mode); | ||
| 213 | } else { | ||
| 214 | rgblight_timer_disable(); | ||
| 215 | _delay_ms(50); | ||
| 216 | rgblight_set(); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | void rgblight_increase_hue(void){ | ||
| 222 | uint16_t hue; | ||
| 223 | hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360; | ||
| 224 | rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); | ||
| 225 | } | ||
| 226 | void rgblight_decrease_hue(void){ | ||
| 227 | uint16_t hue; | ||
| 228 | if (rgblight_config.hue-RGBLIGHT_HUE_STEP <0 ) { | ||
| 229 | hue = (rgblight_config.hue+360-RGBLIGHT_HUE_STEP) % 360; | ||
| 230 | } else { | ||
| 231 | hue = (rgblight_config.hue-RGBLIGHT_HUE_STEP) % 360; | ||
| 232 | } | ||
| 233 | rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); | ||
| 234 | } | ||
| 235 | void rgblight_increase_sat(void) { | ||
| 236 | uint8_t sat; | ||
| 237 | if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) { | ||
| 238 | sat = 255; | ||
| 239 | } else { | ||
| 240 | sat = rgblight_config.sat+RGBLIGHT_SAT_STEP; | ||
| 241 | } | ||
| 242 | rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); | ||
| 243 | } | ||
| 244 | void rgblight_decrease_sat(void){ | ||
| 245 | uint8_t sat; | ||
| 246 | if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) { | ||
| 247 | sat = 0; | ||
| 248 | } else { | ||
| 249 | sat = rgblight_config.sat-RGBLIGHT_SAT_STEP; | ||
| 250 | } | ||
| 251 | rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); | ||
| 252 | } | ||
| 253 | void rgblight_increase_val(void){ | ||
| 254 | uint8_t val; | ||
| 255 | if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) { | ||
| 256 | val = 255; | ||
| 257 | } else { | ||
| 258 | val = rgblight_config.val+RGBLIGHT_VAL_STEP; | ||
| 259 | } | ||
| 260 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); | ||
| 261 | } | ||
| 262 | void rgblight_decrease_val(void) { | ||
| 263 | uint8_t val; | ||
| 264 | if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) { | ||
| 265 | val = 0; | ||
| 266 | } else { | ||
| 267 | val = rgblight_config.val-RGBLIGHT_VAL_STEP; | ||
| 268 | } | ||
| 269 | rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); | ||
| 270 | } | ||
| 271 | |||
| 272 | void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val){ | ||
| 273 | inmem_config.raw = rgblight_config.raw; | ||
| 274 | if (rgblight_config.enable) { | ||
| 275 | struct cRGB tmp_led; | ||
| 276 | sethsv(hue, sat, val, &tmp_led); | ||
| 277 | inmem_config.hue = hue; | ||
| 278 | inmem_config.sat = sat; | ||
| 279 | inmem_config.val = val; | ||
| 280 | // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val); | ||
| 281 | rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val){ | ||
| 285 | if (rgblight_config.enable) { | ||
| 286 | if (rgblight_config.mode == 1) { | ||
| 287 | // same static color | ||
| 288 | rgblight_sethsv_noeeprom(hue, sat, val); | ||
| 289 | } else { | ||
| 290 | // all LEDs in same color | ||
| 291 | if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { | ||
| 292 | // breathing mode, ignore the change of val, use in memory value instead | ||
| 293 | val = rgblight_config.val; | ||
| 294 | } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) { | ||
| 295 | // rainbow mood and rainbow swirl, ignore the change of hue | ||
| 296 | hue = rgblight_config.hue; | ||
| 297 | } | ||
| 298 | } | ||
| 299 | rgblight_config.hue = hue; | ||
| 300 | rgblight_config.sat = sat; | ||
| 301 | rgblight_config.val = val; | ||
| 302 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 303 | xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b){ | ||
| 308 | // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b); | ||
| 309 | for (uint8_t i=0;i<RGBLED_NUM;i++) { | ||
| 310 | led[i].r = r; | ||
| 311 | led[i].g = g; | ||
| 312 | led[i].b = b; | ||
| 313 | } | ||
| 314 | rgblight_set(); | ||
| 315 | |||
| 316 | } | ||
| 317 | |||
| 318 | void rgblight_set(void) { | ||
| 319 | if (rgblight_config.enable) { | ||
| 320 | ws2812_setleds(led, RGBLED_NUM); | ||
| 321 | } else { | ||
| 322 | for (uint8_t i=0;i<RGBLED_NUM;i++) { | ||
| 323 | led[i].r = 0; | ||
| 324 | led[i].g = 0; | ||
| 325 | led[i].b = 0; | ||
| 326 | } | ||
| 327 | ws2812_setleds(led, RGBLED_NUM); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | // Animation timer -- AVR Timer3 | ||
| 332 | void rgblight_timer_init(void) { | ||
| 333 | static uint8_t rgblight_timer_is_init = 0; | ||
| 334 | if (rgblight_timer_is_init) { | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | rgblight_timer_is_init = 1; | ||
| 338 | /* Timer 3 setup */ | ||
| 339 | TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP | ||
| 340 | | _BV(CS30); //Clock selelct: clk/1 | ||
| 341 | /* Set TOP value */ | ||
| 342 | uint8_t sreg = SREG; | ||
| 343 | cli(); | ||
| 344 | OCR3AH = (RGBLED_TIMER_TOP>>8)&0xff; | ||
| 345 | OCR3AL = RGBLED_TIMER_TOP&0xff; | ||
| 346 | SREG = sreg; | ||
| 347 | } | ||
| 348 | void rgblight_timer_enable(void) { | ||
| 349 | TIMSK3 |= _BV(OCIE3A); | ||
| 350 | dprintf("TIMER3 enabled.\n"); | ||
| 351 | } | ||
| 352 | void rgblight_timer_disable(void) { | ||
| 353 | TIMSK3 &= ~_BV(OCIE3A); | ||
| 354 | dprintf("TIMER3 disabled.\n"); | ||
| 355 | } | ||
| 356 | void rgblight_timer_toggle(void) { | ||
| 357 | TIMSK3 ^= _BV(OCIE3A); | ||
| 358 | dprintf("TIMER3 toggled.\n"); | ||
| 359 | } | ||
| 360 | |||
| 361 | ISR(TIMER3_COMPA_vect) { | ||
| 362 | // Mode = 1, static light, do nothing here | ||
| 363 | if (rgblight_config.mode>=2 && rgblight_config.mode<=5) { | ||
| 364 | // mode = 2 to 5, breathing mode | ||
| 365 | rgblight_effect_breathing(rgblight_config.mode-2); | ||
| 366 | |||
| 367 | } else if (rgblight_config.mode>=6 && rgblight_config.mode<=8) { | ||
| 368 | rgblight_effect_rainbow_mood(rgblight_config.mode-6); | ||
| 369 | } else if (rgblight_config.mode>=9 && rgblight_config.mode<=14) { | ||
| 370 | rgblight_effect_rainbow_swirl(rgblight_config.mode-9); | ||
| 371 | } else if (rgblight_config.mode>=15 && rgblight_config.mode<=20) { | ||
| 372 | rgblight_effect_snake(rgblight_config.mode-15); | ||
| 373 | } else if (rgblight_config.mode>=21 && rgblight_config.mode<=23) { | ||
| 374 | rgblight_effect_knight(rgblight_config.mode-21); | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | // effects | ||
| 379 | void rgblight_effect_breathing(uint8_t interval) { | ||
| 380 | static uint8_t pos = 0; | ||
| 381 | static uint16_t last_timer = 0; | ||
| 382 | |||
| 383 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) return; | ||
| 384 | last_timer = timer_read(); | ||
| 385 | |||
| 386 | rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos])); | ||
| 387 | pos = (pos+1) % 256; | ||
| 388 | } | ||
| 389 | |||
| 390 | void rgblight_effect_rainbow_mood(uint8_t interval) { | ||
| 391 | static uint16_t current_hue=0; | ||
| 392 | static uint16_t last_timer = 0; | ||
| 393 | |||
| 394 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) return; | ||
| 395 | last_timer = timer_read(); | ||
| 396 | rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val); | ||
| 397 | current_hue = (current_hue+1) % 360; | ||
| 398 | } | ||
| 399 | |||
| 400 | void rgblight_effect_rainbow_swirl(uint8_t interval) { | ||
| 401 | static uint16_t current_hue=0; | ||
| 402 | static uint16_t last_timer = 0; | ||
| 403 | uint16_t hue; | ||
| 404 | uint8_t i; | ||
| 405 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval/2])) return; | ||
| 406 | last_timer = timer_read(); | ||
| 407 | for (i=0; i<RGBLED_NUM; i++) { | ||
| 408 | hue = (360/RGBLED_NUM*i+current_hue)%360; | ||
| 409 | sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]); | ||
| 410 | } | ||
| 411 | rgblight_set(); | ||
| 412 | |||
| 413 | if (interval % 2) { | ||
| 414 | current_hue = (current_hue+1) % 360; | ||
| 415 | } else { | ||
| 416 | if (current_hue -1 < 0) { | ||
| 417 | current_hue = 359; | ||
| 418 | } else { | ||
| 419 | current_hue = current_hue - 1; | ||
| 420 | } | ||
| 421 | |||
| 422 | } | ||
| 423 | } | ||
| 424 | void rgblight_effect_snake(uint8_t interval) { | ||
| 425 | static uint8_t pos=0; | ||
| 426 | static uint16_t last_timer = 0; | ||
| 427 | uint8_t i,j; | ||
| 428 | int8_t k; | ||
| 429 | int8_t increament = 1; | ||
| 430 | if (interval%2) increament = -1; | ||
| 431 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval/2])) return; | ||
| 432 | last_timer = timer_read(); | ||
| 433 | for (i=0;i<RGBLED_NUM;i++) { | ||
| 434 | led[i].r=0; | ||
| 435 | led[i].g=0; | ||
| 436 | led[i].b=0; | ||
| 437 | for (j=0;j<RGBLIGHT_EFFECT_SNAKE_LENGTH;j++) { | ||
| 438 | k = pos+j*increament; | ||
| 439 | if (k<0) k = k+RGBLED_NUM; | ||
| 440 | if (i==k) { | ||
| 441 | sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | } | ||
| 445 | rgblight_set(); | ||
| 446 | if (increament == 1) { | ||
| 447 | if (pos - 1 < 0) { | ||
| 448 | pos = RGBLED_NUM-1; | ||
| 449 | } else { | ||
| 450 | pos -= 1; | ||
| 451 | } | ||
| 452 | } else { | ||
| 453 | pos = (pos+1)%RGBLED_NUM; | ||
| 454 | } | ||
| 455 | |||
| 456 | } | ||
| 457 | |||
| 458 | void rgblight_effect_knight(uint8_t interval) { | ||
| 459 | static int8_t pos=0; | ||
| 460 | static uint16_t last_timer = 0; | ||
| 461 | uint8_t i,j,cur; | ||
| 462 | int8_t k; | ||
| 463 | struct cRGB preled[RGBLED_NUM]; | ||
| 464 | static int8_t increament = -1; | ||
| 465 | if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) return; | ||
| 466 | last_timer = timer_read(); | ||
| 467 | for (i=0;i<RGBLED_NUM;i++) { | ||
| 468 | preled[i].r=0; | ||
| 469 | preled[i].g=0; | ||
| 470 | preled[i].b=0; | ||
| 471 | for (j=0;j<RGBLIGHT_EFFECT_KNIGHT_LENGTH;j++) { | ||
| 472 | k = pos+j*increament; | ||
| 473 | if (k<0) k = 0; | ||
| 474 | if (k>=RGBLED_NUM) k=RGBLED_NUM-1; | ||
| 475 | if (i==k) { | ||
| 476 | sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | } | ||
| 480 | if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) { | ||
| 481 | for (i=0;i<RGBLED_NUM;i++) { | ||
| 482 | cur = (i+RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM; | ||
| 483 | led[i].r = preled[cur].r; | ||
| 484 | led[i].g = preled[cur].g; | ||
| 485 | led[i].b = preled[cur].b; | ||
| 486 | } | ||
| 487 | } | ||
| 488 | rgblight_set(); | ||
| 489 | if (increament == 1) { | ||
| 490 | if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) { | ||
| 491 | pos = 0- RGBLIGHT_EFFECT_KNIGHT_LENGTH; | ||
| 492 | increament = -1; | ||
| 493 | } else { | ||
| 494 | pos -= 1; | ||
| 495 | } | ||
| 496 | } else { | ||
| 497 | if (pos+1>RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH) { | ||
| 498 | pos = RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH-1; | ||
| 499 | increament = 1; | ||
| 500 | } else { | ||
| 501 | pos += 1; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | } | ||
diff --git a/quantum/rgblight.h b/quantum/rgblight.h new file mode 100644 index 000000000..64f92523e --- /dev/null +++ b/quantum/rgblight.h | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | #ifndef RGBLIGHT_H | ||
| 2 | #define RGBLIGHT_H | ||
| 3 | |||
| 4 | #ifndef RGBLIGHT_MODES | ||
| 5 | #define RGBLIGHT_MODES 23 | ||
| 6 | #endif | ||
| 7 | |||
| 8 | #ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH | ||
| 9 | #define RGBLIGHT_EFFECT_SNAKE_LENGTH 7 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #ifndef RGBLIGHT_EFFECT_KNIGHT_LENGTH | ||
| 13 | #define RGBLIGHT_EFFECT_KNIGHT_LENGTH 7 | ||
| 14 | #endif | ||
| 15 | #ifndef RGBLIGHT_EFFECT_KNIGHT_OFFSET | ||
| 16 | #define RGBLIGHT_EFFECT_KNIGHT_OFFSET 9 | ||
| 17 | #endif | ||
| 18 | |||
| 19 | #ifndef RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH | ||
| 20 | #define RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH 4 | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #ifndef RGBLIGHT_HUE_STEP | ||
| 24 | #define RGBLIGHT_HUE_STEP 10 | ||
| 25 | #endif | ||
| 26 | #ifndef RGBLIGHT_SAT_STEP | ||
| 27 | #define RGBLIGHT_SAT_STEP 17 | ||
| 28 | #endif | ||
| 29 | #ifndef RGBLIGHT_VAL_STEP | ||
| 30 | #define RGBLIGHT_VAL_STEP 17 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #define RGBLED_TIMER_TOP F_CPU/(256*64) | ||
| 34 | |||
| 35 | #include <stdint.h> | ||
| 36 | #include <stdbool.h> | ||
| 37 | #include "eeconfig.h" | ||
| 38 | #include "light_ws2812.h" | ||
| 39 | |||
| 40 | typedef union { | ||
| 41 | uint32_t raw; | ||
| 42 | struct { | ||
| 43 | bool enable :1; | ||
| 44 | uint8_t mode :6; | ||
| 45 | uint16_t hue :9; | ||
| 46 | uint8_t sat :8; | ||
| 47 | uint8_t val :8; | ||
| 48 | }; | ||
| 49 | } rgblight_config_t; | ||
| 50 | |||
| 51 | void rgblight_init(void); | ||
| 52 | void rgblight_increase(void); | ||
| 53 | void rgblight_decrease(void); | ||
| 54 | void rgblight_toggle(void); | ||
| 55 | void rgblight_step(void); | ||
| 56 | void rgblight_mode(uint8_t mode); | ||
| 57 | void rgblight_set(void); | ||
| 58 | void rgblight_increase_hue(void); | ||
| 59 | void rgblight_decrease_hue(void); | ||
| 60 | void rgblight_increase_sat(void); | ||
| 61 | void rgblight_decrease_sat(void); | ||
| 62 | void rgblight_increase_val(void); | ||
| 63 | void rgblight_decrease_val(void); | ||
| 64 | void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val); | ||
| 65 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b); | ||
| 66 | |||
| 67 | uint32_t eeconfig_read_rgblight(void); | ||
| 68 | void eeconfig_update_rgblight(uint32_t val); | ||
| 69 | void eeconfig_update_rgblight_default(void); | ||
| 70 | void eeconfig_debug_rgblight(void); | ||
| 71 | |||
| 72 | void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); | ||
| 73 | void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1); | ||
| 74 | void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val); | ||
| 75 | |||
| 76 | void rgblight_timer_init(void); | ||
| 77 | void rgblight_timer_enable(void); | ||
| 78 | void rgblight_timer_disable(void); | ||
| 79 | void rgblight_timer_toggle(void); | ||
| 80 | void rgblight_effect_breathing(uint8_t interval); | ||
| 81 | void rgblight_effect_rainbow_mood(uint8_t interval); | ||
| 82 | void rgblight_effect_rainbow_swirl(uint8_t interval); | ||
| 83 | void rgblight_effect_snake(uint8_t interval); | ||
| 84 | void rgblight_effect_knight(uint8_t interval); | ||
| 85 | |||
| 86 | #endif | ||
diff --git a/quantum/serial_link/.gitignore b/quantum/serial_link/.gitignore new file mode 100644 index 000000000..2d68e206e --- /dev/null +++ b/quantum/serial_link/.gitignore | |||
| @@ -0,0 +1 @@ | |||
| *.stackdump | |||
diff --git a/quantum/serial_link/.gitmodules b/quantum/serial_link/.gitmodules new file mode 100644 index 000000000..991cfe96d --- /dev/null +++ b/quantum/serial_link/.gitmodules | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | [submodule "cgreen/cgreen"] | ||
| 2 | path = cgreen/cgreen | ||
| 3 | url = http://github.com/cgreen-devs/cgreen | ||
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..94af9125c --- /dev/null +++ b/quantum/serial_link/README.md | |||
| @@ -0,0 +1 @@ | |||
| # tmk_serial_link \ No newline at end of file | |||
diff --git a/quantum/serial_link/cgreen/Makefile b/quantum/serial_link/cgreen/Makefile new file mode 100644 index 000000000..6b31a3f92 --- /dev/null +++ b/quantum/serial_link/cgreen/Makefile | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | # This Makefile ensures that the build is made out of source in a subdirectory called 'build' | ||
| 2 | # If it doesn't exist, it is created and a Makefile created there (from Makefile.build) | ||
| 3 | # | ||
| 4 | # This Makefile also contains delegation of the most common make commands | ||
| 5 | # | ||
| 6 | # If you have cmake installed you should be able to do: | ||
| 7 | # | ||
| 8 | # make | ||
| 9 | # make test | ||
| 10 | # make install | ||
| 11 | # make package | ||
| 12 | # | ||
| 13 | # That should build cgreen for C and C++, run some tests, install it locally and | ||
| 14 | # generate two distributable packages. | ||
| 15 | |||
| 16 | all: build | ||
| 17 | cd $(CGREEN_BUILD_DIR); make all | ||
| 18 | |||
| 19 | test: build | ||
| 20 | cd $(CGREEN_BUILD_DIR); make test | ||
| 21 | |||
| 22 | clean: build | ||
| 23 | cd $(CGREEN_BUILD_DIR); make clean | ||
| 24 | |||
| 25 | package: build | ||
| 26 | cd $(CGREEN_BUILD_DIR); make package | ||
| 27 | |||
| 28 | install: | ||
| 29 | cd $(CGREEN_BUILD_DIR); make install | ||
| 30 | |||
| 31 | ############# Internal | ||
| 32 | |||
| 33 | build: | ||
| 34 | mkdir -p $(CGREEN_BUILD_DIR) | ||
| 35 | cp Makefile.build $(CGREEN_BUILD_DIR)/Makefile | ||
| 36 | |||
| 37 | |||
| 38 | .SILENT: | ||
diff --git a/quantum/serial_link/cgreen/Makefile.build b/quantum/serial_link/cgreen/Makefile.build new file mode 100644 index 000000000..f76165244 --- /dev/null +++ b/quantum/serial_link/cgreen/Makefile.build | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # This Makefile is copied from the cgreen top directory (where it is | ||
| 2 | # named Makefile.build) and put in a subdirectory called 'build' where | ||
| 3 | # builds are made This Makefile then automatically creates | ||
| 4 | # subdirectories for C and C++ builds configuring them using the cmake | ||
| 5 | # command. Once created you can always tweak the cmake setup as with | ||
| 6 | # any cmake build directory | ||
| 7 | |||
| 8 | all: build-c build-c++ | ||
| 9 | for d in build-* ; do cd $$d; make ; cd .. ; done | ||
| 10 | |||
| 11 | clean: | ||
| 12 | for d in build-* ; do cd $$d; make clean ; cd .. ; done | ||
| 13 | |||
| 14 | check test: | ||
| 15 | for d in build-* ; do cd $$d; make check ; cd .. ; done | ||
| 16 | |||
| 17 | package: | ||
| 18 | for d in build-* ; do cd $$d; make package ; cd .. ; done | ||
| 19 | |||
| 20 | install: | ||
| 21 | for d in build-* ; do cd $$d; make install ; cd .. ; done | ||
| 22 | |||
| 23 | ############ Internal | ||
| 24 | |||
| 25 | build-c: | ||
| 26 | mkdir build-c | ||
| 27 | cd build-c; cmake -G "Unix Makefiles" $(CGREEN_DIR) | ||
| 28 | |||
| 29 | build-c++: | ||
| 30 | mkdir build-c++ | ||
| 31 | cd build-c++; cmake -G "Unix Makefiles" -DWITH_CXX:bool=ON $(CGREEN_DIR) | ||
| 32 | |||
| 33 | .SILENT: | ||
diff --git a/quantum/serial_link/cgreen/cgreen b/quantum/serial_link/cgreen/cgreen new file mode 160000 | |||
| Subproject d4d438dda1b7131f0bd0530b2c258e9dea6a2a9 | |||
diff --git a/quantum/serial_link/serial_link.mk b/quantum/serial_link/serial_link.mk new file mode 100644 index 000000000..e164cc5ff --- /dev/null +++ b/quantum/serial_link/serial_link.mk | |||
| @@ -0,0 +1,27 @@ | |||
| 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 | UINCDIR += $(SERIAL_DIR) | ||
| 24 | SRC += $(wildcard $(SERIAL_DIR)/serial_link/protocol/*.c) | ||
| 25 | SRC += $(wildcard $(SERIAL_DIR)/serial_link/system/*.c) | ||
| 26 | SRC += serial_link_hal.c | ||
| 27 | OPT_DEFS += -DUSE_SERIAL_LINK | ||
diff --git a/quantum/serial_link/serial_link/protocol/byte_stuffer.c b/quantum/serial_link/serial_link/protocol/byte_stuffer.c new file mode 100644 index 000000000..fb4c45a8d --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/byte_stuffer.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 26 | #include "serial_link/protocol/frame_validator.h" | ||
| 27 | #include "serial_link/protocol/physical.h" | ||
| 28 | #include <stdbool.h> | ||
| 29 | |||
| 30 | // This implements the "Consistent overhead byte stuffing protocol" | ||
| 31 | // https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing | ||
| 32 | // http://www.stuartcheshire.org/papers/COBSforToN.pdf | ||
| 33 | |||
| 34 | #define MAX_FRAME_SIZE 1024 | ||
| 35 | #define NUM_LINKS 2 | ||
| 36 | |||
| 37 | typedef struct byte_stuffer_state { | ||
| 38 | uint16_t next_zero; | ||
| 39 | uint16_t data_pos; | ||
| 40 | bool long_frame; | ||
| 41 | uint8_t data[MAX_FRAME_SIZE]; | ||
| 42 | }byte_stuffer_state_t; | ||
| 43 | |||
| 44 | static byte_stuffer_state_t states[NUM_LINKS]; | ||
| 45 | |||
| 46 | void init_byte_stuffer_state(byte_stuffer_state_t* state) { | ||
| 47 | state->next_zero = 0; | ||
| 48 | state->data_pos = 0; | ||
| 49 | state->long_frame = false; | ||
| 50 | } | ||
| 51 | |||
| 52 | void init_byte_stuffer(void) { | ||
| 53 | int i; | ||
| 54 | for (i=0;i<NUM_LINKS;i++) { | ||
| 55 | init_byte_stuffer_state(&states[i]); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data) { | ||
| 60 | byte_stuffer_state_t* state = &states[link]; | ||
| 61 | // Start of a new frame | ||
| 62 | if (state->next_zero == 0) { | ||
| 63 | state->next_zero = data; | ||
| 64 | state->long_frame = data == 0xFF; | ||
| 65 | state->data_pos = 0; | ||
| 66 | return; | ||
| 67 | } | ||
| 68 | |||
| 69 | state->next_zero--; | ||
| 70 | if (data == 0) { | ||
| 71 | if (state->next_zero == 0) { | ||
| 72 | // The frame is completed | ||
| 73 | if (state->data_pos > 0) { | ||
| 74 | validator_recv_frame(link, state->data, state->data_pos); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | else { | ||
| 78 | // The frame is invalid, so reset | ||
| 79 | init_byte_stuffer_state(state); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | else { | ||
| 83 | if (state->data_pos == MAX_FRAME_SIZE) { | ||
| 84 | // We exceeded our maximum frame size | ||
| 85 | // therefore there's nothing else to do than reset to a new frame | ||
| 86 | state->next_zero = data; | ||
| 87 | state->long_frame = data == 0xFF; | ||
| 88 | state->data_pos = 0; | ||
| 89 | } | ||
| 90 | else if (state->next_zero == 0) { | ||
| 91 | if (state->long_frame) { | ||
| 92 | // This is part of a long frame, so continue | ||
| 93 | state->next_zero = data; | ||
| 94 | state->long_frame = data == 0xFF; | ||
| 95 | } | ||
| 96 | else { | ||
| 97 | // Special case for zeroes | ||
| 98 | state->next_zero = data; | ||
| 99 | state->data[state->data_pos++] = 0; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | else { | ||
| 103 | state->data[state->data_pos++] = data; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) { | ||
| 109 | send_data(link, &num_non_zero, 1); | ||
| 110 | if (end > start) { | ||
| 111 | send_data(link, start, end-start); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 116 | const uint8_t zero = 0; | ||
| 117 | if (size > 0) { | ||
| 118 | uint16_t num_non_zero = 1; | ||
| 119 | uint8_t* end = data + size; | ||
| 120 | uint8_t* start = data; | ||
| 121 | while (data < end) { | ||
| 122 | if (num_non_zero == 0xFF) { | ||
| 123 | // There's more data after big non-zero block | ||
| 124 | // So send it, and start a new block | ||
| 125 | send_block(link, start, data, num_non_zero); | ||
| 126 | start = data; | ||
| 127 | num_non_zero = 1; | ||
| 128 | } | ||
| 129 | else { | ||
| 130 | if (*data == 0) { | ||
| 131 | // A zero encountered, so send the block | ||
| 132 | send_block(link, start, data, num_non_zero); | ||
| 133 | start = data + 1; | ||
| 134 | num_non_zero = 1; | ||
| 135 | } | ||
| 136 | else { | ||
| 137 | num_non_zero++; | ||
| 138 | } | ||
| 139 | ++data; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | send_block(link, start, data, num_non_zero); | ||
| 143 | send_data(link, &zero, 1); | ||
| 144 | } | ||
| 145 | } | ||
diff --git a/quantum/serial_link/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/serial_link/protocol/byte_stuffer.h new file mode 100644 index 000000000..2cc88beb4 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/byte_stuffer.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef SERIAL_LINK_BYTE_STUFFER_H | ||
| 26 | #define SERIAL_LINK_BYTE_STUFFER_H | ||
| 27 | |||
| 28 | #include <stdint.h> | ||
| 29 | |||
| 30 | void init_byte_stuffer(void); | ||
| 31 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data); | ||
| 32 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
| 33 | |||
| 34 | #endif | ||
diff --git a/quantum/serial_link/serial_link/protocol/frame_router.c b/quantum/serial_link/serial_link/protocol/frame_router.c new file mode 100644 index 000000000..04b8c2e75 --- /dev/null +++ b/quantum/serial_link/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/serial_link/protocol/frame_router.h b/quantum/serial_link/serial_link/protocol/frame_router.h new file mode 100644 index 000000000..712250ff3 --- /dev/null +++ b/quantum/serial_link/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/serial_link/protocol/frame_validator.c b/quantum/serial_link/serial_link/protocol/frame_validator.c new file mode 100644 index 000000000..474f80ee8 --- /dev/null +++ b/quantum/serial_link/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/serial_link/protocol/frame_validator.h b/quantum/serial_link/serial_link/protocol/frame_validator.h new file mode 100644 index 000000000..4a910d510 --- /dev/null +++ b/quantum/serial_link/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/serial_link/protocol/physical.h b/quantum/serial_link/serial_link/protocol/physical.h new file mode 100644 index 000000000..425e06cdd --- /dev/null +++ b/quantum/serial_link/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/serial_link/protocol/transport.c b/quantum/serial_link/serial_link/protocol/transport.c new file mode 100644 index 000000000..f418d11ce --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/transport.c | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/transport.h" | ||
| 26 | #include "serial_link/protocol/frame_router.h" | ||
| 27 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 28 | #include <string.h> | ||
| 29 | |||
| 30 | #define MAX_REMOTE_OBJECTS 16 | ||
| 31 | static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS]; | ||
| 32 | static uint32_t num_remote_objects = 0; | ||
| 33 | |||
| 34 | void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) { | ||
| 35 | unsigned int i; | ||
| 36 | for(i=0;i<_num_remote_objects;i++) { | ||
| 37 | remote_object_t* obj = _remote_objects[i]; | ||
| 38 | remote_objects[num_remote_objects++] = obj; | ||
| 39 | if (obj->object_type == MASTER_TO_ALL_SLAVES) { | ||
| 40 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; | ||
| 41 | triple_buffer_init(tb); | ||
| 42 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 43 | tb = (triple_buffer_object_t*)start; | ||
| 44 | triple_buffer_init(tb); | ||
| 45 | } | ||
| 46 | else if(obj->object_type == MASTER_TO_SINGLE_SLAVE) { | ||
| 47 | uint8_t* start = obj->buffer; | ||
| 48 | unsigned int j; | ||
| 49 | for (j=0;j<NUM_SLAVES;j++) { | ||
| 50 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 51 | triple_buffer_init(tb); | ||
| 52 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 53 | } | ||
| 54 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 55 | triple_buffer_init(tb); | ||
| 56 | } | ||
| 57 | else { | ||
| 58 | uint8_t* start = obj->buffer; | ||
| 59 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 60 | triple_buffer_init(tb); | ||
| 61 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 62 | unsigned int j; | ||
| 63 | for (j=0;j<NUM_SLAVES;j++) { | ||
| 64 | tb = (triple_buffer_object_t*)start; | ||
| 65 | triple_buffer_init(tb); | ||
| 66 | start += REMOTE_OBJECT_SIZE(obj->object_size); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
| 73 | uint8_t id = data[size-1]; | ||
| 74 | if (id < num_remote_objects) { | ||
| 75 | remote_object_t* obj = remote_objects[id]; | ||
| 76 | if (obj->object_size == size - 1) { | ||
| 77 | uint8_t* start; | ||
| 78 | if (obj->object_type == MASTER_TO_ALL_SLAVES) { | ||
| 79 | start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 80 | } | ||
| 81 | else if(obj->object_type == SLAVE_TO_MASTER) { | ||
| 82 | start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 83 | start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size); | ||
| 84 | } | ||
| 85 | else { | ||
| 86 | start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 87 | } | ||
| 88 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 89 | void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb); | ||
| 90 | memcpy(ptr, data, size - 1); | ||
| 91 | triple_buffer_end_write_internal(tb); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | void update_transport(void) { | ||
| 97 | unsigned int i; | ||
| 98 | for(i=0;i<num_remote_objects;i++) { | ||
| 99 | remote_object_t* obj = remote_objects[i]; | ||
| 100 | if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) { | ||
| 101 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; | ||
| 102 | uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); | ||
| 103 | if (ptr) { | ||
| 104 | ptr[obj->object_size] = i; | ||
| 105 | uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0; | ||
| 106 | router_send_frame(dest, ptr, obj->object_size + 1); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | else { | ||
| 110 | uint8_t* start = obj->buffer; | ||
| 111 | unsigned int j; | ||
| 112 | for (j=0;j<NUM_SLAVES;j++) { | ||
| 113 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 114 | uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); | ||
| 115 | if (ptr) { | ||
| 116 | ptr[obj->object_size] = i; | ||
| 117 | uint8_t dest = j + 1; | ||
| 118 | router_send_frame(dest, ptr, obj->object_size + 1); | ||
| 119 | } | ||
| 120 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/quantum/serial_link/serial_link/protocol/transport.h b/quantum/serial_link/serial_link/protocol/transport.h new file mode 100644 index 000000000..9a052d880 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/transport.h | |||
| @@ -0,0 +1,151 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef SERIAL_LINK_TRANSPORT_H | ||
| 26 | #define SERIAL_LINK_TRANSPORT_H | ||
| 27 | |||
| 28 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 29 | #include "serial_link/system/serial_link.h" | ||
| 30 | |||
| 31 | #define NUM_SLAVES 8 | ||
| 32 | #define LOCAL_OBJECT_EXTRA 16 | ||
| 33 | |||
| 34 | // master -> slave = 1 local(target all), 1 remote object | ||
| 35 | // slave -> master = 1 local(target 0), multiple remote objects | ||
| 36 | // master -> single slave (multiple local, target id), 1 remote object | ||
| 37 | typedef enum { | ||
| 38 | MASTER_TO_ALL_SLAVES, | ||
| 39 | MASTER_TO_SINGLE_SLAVE, | ||
| 40 | SLAVE_TO_MASTER, | ||
| 41 | } remote_object_type; | ||
| 42 | |||
| 43 | typedef struct { | ||
| 44 | remote_object_type object_type; | ||
| 45 | uint16_t object_size; | ||
| 46 | uint8_t buffer[] __attribute__((aligned(4))); | ||
| 47 | } remote_object_t; | ||
| 48 | |||
| 49 | #define REMOTE_OBJECT_SIZE(objectsize) \ | ||
| 50 | (sizeof(triple_buffer_object_t) + objectsize * 3) | ||
| 51 | #define LOCAL_OBJECT_SIZE(objectsize) \ | ||
| 52 | (sizeof(triple_buffer_object_t) + (objectsize + LOCAL_OBJECT_EXTRA) * 3) | ||
| 53 | |||
| 54 | #define REMOTE_OBJECT_HELPER(name, type, num_local, num_remote) \ | ||
| 55 | typedef struct { \ | ||
| 56 | remote_object_t object; \ | ||
| 57 | uint8_t buffer[ \ | ||
| 58 | num_remote * REMOTE_OBJECT_SIZE(sizeof(type)) + \ | ||
| 59 | num_local * LOCAL_OBJECT_SIZE(sizeof(type))]; \ | ||
| 60 | } remote_object_##name##_t; | ||
| 61 | |||
| 62 | #define MASTER_TO_ALL_SLAVES_OBJECT(name, type) \ | ||
| 63 | REMOTE_OBJECT_HELPER(name, type, 1, 1) \ | ||
| 64 | remote_object_##name##_t remote_object_##name = { \ | ||
| 65 | .object = { \ | ||
| 66 | .object_type = MASTER_TO_ALL_SLAVES, \ | ||
| 67 | .object_size = sizeof(type), \ | ||
| 68 | } \ | ||
| 69 | }; \ | ||
| 70 | type* begin_write_##name(void) { \ | ||
| 71 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 72 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 73 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 74 | }\ | ||
| 75 | void end_write_##name(void) { \ | ||
| 76 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 77 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 78 | triple_buffer_end_write_internal(tb); \ | ||
| 79 | signal_data_written(); \ | ||
| 80 | }\ | ||
| 81 | type* read_##name(void) { \ | ||
| 82 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 83 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ | ||
| 84 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 85 | return triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 86 | } | ||
| 87 | |||
| 88 | #define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \ | ||
| 89 | REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \ | ||
| 90 | remote_object_##name##_t remote_object_##name = { \ | ||
| 91 | .object = { \ | ||
| 92 | .object_type = MASTER_TO_SINGLE_SLAVE, \ | ||
| 93 | .object_size = sizeof(type), \ | ||
| 94 | } \ | ||
| 95 | }; \ | ||
| 96 | type* begin_write_##name(uint8_t slave) { \ | ||
| 97 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 98 | uint8_t* start = obj->buffer;\ | ||
| 99 | start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 100 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 101 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 102 | }\ | ||
| 103 | void end_write_##name(uint8_t slave) { \ | ||
| 104 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 105 | uint8_t* start = obj->buffer;\ | ||
| 106 | start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 107 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 108 | triple_buffer_end_write_internal(tb); \ | ||
| 109 | signal_data_written(); \ | ||
| 110 | }\ | ||
| 111 | type* read_##name() { \ | ||
| 112 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 113 | uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\ | ||
| 114 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 115 | return triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 116 | } | ||
| 117 | |||
| 118 | #define SLAVE_TO_MASTER_OBJECT(name, type) \ | ||
| 119 | REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \ | ||
| 120 | remote_object_##name##_t remote_object_##name = { \ | ||
| 121 | .object = { \ | ||
| 122 | .object_type = SLAVE_TO_MASTER, \ | ||
| 123 | .object_size = sizeof(type), \ | ||
| 124 | } \ | ||
| 125 | }; \ | ||
| 126 | type* begin_write_##name(void) { \ | ||
| 127 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 128 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 129 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 130 | }\ | ||
| 131 | void end_write_##name(void) { \ | ||
| 132 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 133 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 134 | triple_buffer_end_write_internal(tb); \ | ||
| 135 | signal_data_written(); \ | ||
| 136 | }\ | ||
| 137 | type* read_##name(uint8_t slave) { \ | ||
| 138 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 139 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ | ||
| 140 | start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \ | ||
| 141 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 142 | return triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 143 | } | ||
| 144 | |||
| 145 | #define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name | ||
| 146 | |||
| 147 | void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); | ||
| 148 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); | ||
| 149 | void update_transport(void); | ||
| 150 | |||
| 151 | #endif | ||
diff --git a/quantum/serial_link/serial_link/protocol/triple_buffered_object.c b/quantum/serial_link/serial_link/protocol/triple_buffered_object.c new file mode 100644 index 000000000..e3e8989d3 --- /dev/null +++ b/quantum/serial_link/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/serial_link/protocol/triple_buffered_object.h b/quantum/serial_link/serial_link/protocol/triple_buffered_object.h new file mode 100644 index 000000000..2e57db3f5 --- /dev/null +++ b/quantum/serial_link/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/serial_link/system/serial_link.c b/quantum/serial_link/serial_link/system/serial_link.c new file mode 100644 index 000000000..75c7e77a7 --- /dev/null +++ b/quantum/serial_link/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/serial_link/system/serial_link.h b/quantum/serial_link/serial_link/system/serial_link.h new file mode 100644 index 000000000..351e03877 --- /dev/null +++ b/quantum/serial_link/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/serial_link/tests/Makefile b/quantum/serial_link/serial_link/tests/Makefile new file mode 100644 index 000000000..1b072c6f1 --- /dev/null +++ b/quantum/serial_link/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/serial_link/tests/byte_stuffer_tests.c b/quantum/serial_link/serial_link/tests/byte_stuffer_tests.c new file mode 100644 index 000000000..64b170e8c --- /dev/null +++ b/quantum/serial_link/serial_link/tests/byte_stuffer_tests.c | |||
| @@ -0,0 +1,506 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <cgreen/cgreen.h> | ||
| 26 | #include <cgreen/mocks.h> | ||
| 27 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 28 | #include "serial_link/protocol/byte_stuffer.c" | ||
| 29 | #include "serial_link/protocol/frame_validator.h" | ||
| 30 | #include "serial_link/protocol/physical.h" | ||
| 31 | |||
| 32 | static uint8_t sent_data[MAX_FRAME_SIZE*2]; | ||
| 33 | static uint16_t sent_data_size; | ||
| 34 | |||
| 35 | Describe(ByteStuffer); | ||
| 36 | BeforeEach(ByteStuffer) { | ||
| 37 | init_byte_stuffer(); | ||
| 38 | sent_data_size = 0; | ||
| 39 | } | ||
| 40 | AfterEach(ByteStuffer) {} | ||
| 41 | |||
| 42 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 43 | mock(data, size); | ||
| 44 | } | ||
| 45 | |||
| 46 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 47 | memcpy(sent_data + sent_data_size, data, size); | ||
| 48 | sent_data_size += size; | ||
| 49 | } | ||
| 50 | |||
| 51 | Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { | ||
| 52 | never_expect(validator_recv_frame); | ||
| 53 | byte_stuffer_recv_byte(0, 0); | ||
| 54 | } | ||
| 55 | |||
| 56 | Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { | ||
| 57 | never_expect(validator_recv_frame); | ||
| 58 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 59 | } | ||
| 60 | |||
| 61 | Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) { | ||
| 62 | never_expect(validator_recv_frame); | ||
| 63 | byte_stuffer_recv_byte(0, 0x4A); | ||
| 64 | } | ||
| 65 | |||
| 66 | Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) { | ||
| 67 | never_expect(validator_recv_frame); | ||
| 68 | byte_stuffer_recv_byte(0, 1); | ||
| 69 | byte_stuffer_recv_byte(0, 0); | ||
| 70 | } | ||
| 71 | |||
| 72 | Ensure(ByteStuffer, receives_single_byte_valid_frame) { | ||
| 73 | uint8_t expected[] = {0x37}; | ||
| 74 | expect(validator_recv_frame, | ||
| 75 | when(size, is_equal_to(1)), | ||
| 76 | when(data, is_equal_to_contents_of(expected, 1)) | ||
| 77 | ); | ||
| 78 | byte_stuffer_recv_byte(0, 2); | ||
| 79 | byte_stuffer_recv_byte(0, 0x37); | ||
| 80 | byte_stuffer_recv_byte(0, 0); | ||
| 81 | } | ||
| 82 | |||
| 83 | Ensure(ByteStuffer, receives_three_bytes_valid_frame) { | ||
| 84 | uint8_t expected[] = {0x37, 0x99, 0xFF}; | ||
| 85 | expect(validator_recv_frame, | ||
| 86 | when(size, is_equal_to(3)), | ||
| 87 | when(data, is_equal_to_contents_of(expected, 3)) | ||
| 88 | ); | ||
| 89 | byte_stuffer_recv_byte(0, 4); | ||
| 90 | byte_stuffer_recv_byte(0, 0x37); | ||
| 91 | byte_stuffer_recv_byte(0, 0x99); | ||
| 92 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 93 | byte_stuffer_recv_byte(0, 0); | ||
| 94 | } | ||
| 95 | |||
| 96 | Ensure(ByteStuffer, receives_single_zero_valid_frame) { | ||
| 97 | uint8_t expected[] = {0}; | ||
| 98 | expect(validator_recv_frame, | ||
| 99 | when(size, is_equal_to(1)), | ||
| 100 | when(data, is_equal_to_contents_of(expected, 1)) | ||
| 101 | ); | ||
| 102 | byte_stuffer_recv_byte(0, 1); | ||
| 103 | byte_stuffer_recv_byte(0, 1); | ||
| 104 | byte_stuffer_recv_byte(0, 0); | ||
| 105 | } | ||
| 106 | |||
| 107 | Ensure(ByteStuffer, receives_valid_frame_with_zeroes) { | ||
| 108 | uint8_t expected[] = {5, 0, 3, 0}; | ||
| 109 | expect(validator_recv_frame, | ||
| 110 | when(size, is_equal_to(4)), | ||
| 111 | when(data, is_equal_to_contents_of(expected, 4)) | ||
| 112 | ); | ||
| 113 | byte_stuffer_recv_byte(0, 2); | ||
| 114 | byte_stuffer_recv_byte(0, 5); | ||
| 115 | byte_stuffer_recv_byte(0, 2); | ||
| 116 | byte_stuffer_recv_byte(0, 3); | ||
| 117 | byte_stuffer_recv_byte(0, 1); | ||
| 118 | byte_stuffer_recv_byte(0, 0); | ||
| 119 | } | ||
| 120 | |||
| 121 | Ensure(ByteStuffer, receives_two_valid_frames) { | ||
| 122 | uint8_t expected1[] = {5, 0}; | ||
| 123 | uint8_t expected2[] = {3}; | ||
| 124 | expect(validator_recv_frame, | ||
| 125 | when(size, is_equal_to(2)), | ||
| 126 | when(data, is_equal_to_contents_of(expected1, 2)) | ||
| 127 | ); | ||
| 128 | expect(validator_recv_frame, | ||
| 129 | when(size, is_equal_to(1)), | ||
| 130 | when(data, is_equal_to_contents_of(expected2, 1)) | ||
| 131 | ); | ||
| 132 | byte_stuffer_recv_byte(1, 2); | ||
| 133 | byte_stuffer_recv_byte(1, 5); | ||
| 134 | byte_stuffer_recv_byte(1, 1); | ||
| 135 | byte_stuffer_recv_byte(1, 0); | ||
| 136 | byte_stuffer_recv_byte(1, 2); | ||
| 137 | byte_stuffer_recv_byte(1, 3); | ||
| 138 | byte_stuffer_recv_byte(1, 0); | ||
| 139 | } | ||
| 140 | |||
| 141 | Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) { | ||
| 142 | uint8_t expected[] = {5, 7}; | ||
| 143 | expect(validator_recv_frame, | ||
| 144 | when(size, is_equal_to(2)), | ||
| 145 | when(data, is_equal_to_contents_of(expected, 2)) | ||
| 146 | ); | ||
| 147 | byte_stuffer_recv_byte(1, 3); | ||
| 148 | byte_stuffer_recv_byte(1, 1); | ||
| 149 | byte_stuffer_recv_byte(1, 0); | ||
| 150 | byte_stuffer_recv_byte(1, 3); | ||
| 151 | byte_stuffer_recv_byte(1, 5); | ||
| 152 | byte_stuffer_recv_byte(1, 7); | ||
| 153 | byte_stuffer_recv_byte(1, 0); | ||
| 154 | } | ||
| 155 | |||
| 156 | Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { | ||
| 157 | uint8_t expected[] = {5, 7}; | ||
| 158 | expect(validator_recv_frame, | ||
| 159 | when(size, is_equal_to(2)), | ||
| 160 | when(data, is_equal_to_contents_of(expected, 2)) | ||
| 161 | ); | ||
| 162 | byte_stuffer_recv_byte(0, 2); | ||
| 163 | byte_stuffer_recv_byte(0, 9); | ||
| 164 | byte_stuffer_recv_byte(0, 4); // This should have been zero | ||
| 165 | byte_stuffer_recv_byte(0, 0); | ||
| 166 | byte_stuffer_recv_byte(0, 3); | ||
| 167 | byte_stuffer_recv_byte(0, 5); | ||
| 168 | byte_stuffer_recv_byte(0, 7); | ||
| 169 | byte_stuffer_recv_byte(0, 0); | ||
| 170 | } | ||
| 171 | |||
| 172 | Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) { | ||
| 173 | uint8_t expected[254]; | ||
| 174 | int i; | ||
| 175 | for (i=0;i<254;i++) { | ||
| 176 | expected[i] = i + 1; | ||
| 177 | } | ||
| 178 | expect(validator_recv_frame, | ||
| 179 | when(size, is_equal_to(254)), | ||
| 180 | when(data, is_equal_to_contents_of(expected, 254)) | ||
| 181 | ); | ||
| 182 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 183 | for (i=0;i<254;i++) { | ||
| 184 | byte_stuffer_recv_byte(0, i+1); | ||
| 185 | } | ||
| 186 | byte_stuffer_recv_byte(0, 0); | ||
| 187 | } | ||
| 188 | |||
| 189 | Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) { | ||
| 190 | uint8_t expected[255]; | ||
| 191 | int i; | ||
| 192 | for (i=0;i<254;i++) { | ||
| 193 | expected[i] = i + 1; | ||
| 194 | } | ||
| 195 | expected[254] = 7; | ||
| 196 | expect(validator_recv_frame, | ||
| 197 | when(size, is_equal_to(255)), | ||
| 198 | when(data, is_equal_to_contents_of(expected, 255)) | ||
| 199 | ); | ||
| 200 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 201 | for (i=0;i<254;i++) { | ||
| 202 | byte_stuffer_recv_byte(0, i+1); | ||
| 203 | } | ||
| 204 | byte_stuffer_recv_byte(0, 2); | ||
| 205 | byte_stuffer_recv_byte(0, 7); | ||
| 206 | byte_stuffer_recv_byte(0, 0); | ||
| 207 | } | ||
| 208 | |||
| 209 | Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) { | ||
| 210 | uint8_t expected[255]; | ||
| 211 | int i; | ||
| 212 | for (i=0;i<254;i++) { | ||
| 213 | expected[i] = i + 1; | ||
| 214 | } | ||
| 215 | expected[254] = 0; | ||
| 216 | expect(validator_recv_frame, | ||
| 217 | when(size, is_equal_to(255)), | ||
| 218 | when(data, is_equal_to_contents_of(expected, 255)) | ||
| 219 | ); | ||
| 220 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 221 | for (i=0;i<254;i++) { | ||
| 222 | byte_stuffer_recv_byte(0, i+1); | ||
| 223 | } | ||
| 224 | byte_stuffer_recv_byte(0, 1); | ||
| 225 | byte_stuffer_recv_byte(0, 1); | ||
| 226 | byte_stuffer_recv_byte(0, 0); | ||
| 227 | } | ||
| 228 | |||
| 229 | Ensure(ByteStuffer, receives_two_long_frames_and_some_more) { | ||
| 230 | uint8_t expected[515]; | ||
| 231 | int i; | ||
| 232 | int j; | ||
| 233 | for (j=0;j<2;j++) { | ||
| 234 | for (i=0;i<254;i++) { | ||
| 235 | expected[i+254*j] = i + 1; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | for (i=0;i<7;i++) { | ||
| 239 | expected[254*2+i] = i + 1; | ||
| 240 | } | ||
| 241 | expect(validator_recv_frame, | ||
| 242 | when(size, is_equal_to(515)), | ||
| 243 | when(data, is_equal_to_contents_of(expected, 510)) | ||
| 244 | ); | ||
| 245 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 246 | for (i=0;i<254;i++) { | ||
| 247 | byte_stuffer_recv_byte(0, i+1); | ||
| 248 | } | ||
| 249 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 250 | for (i=0;i<254;i++) { | ||
| 251 | byte_stuffer_recv_byte(0, i+1); | ||
| 252 | } | ||
| 253 | byte_stuffer_recv_byte(0, 8); | ||
| 254 | byte_stuffer_recv_byte(0, 1); | ||
| 255 | byte_stuffer_recv_byte(0, 2); | ||
| 256 | byte_stuffer_recv_byte(0, 3); | ||
| 257 | byte_stuffer_recv_byte(0, 4); | ||
| 258 | byte_stuffer_recv_byte(0, 5); | ||
| 259 | byte_stuffer_recv_byte(0, 6); | ||
| 260 | byte_stuffer_recv_byte(0, 7); | ||
| 261 | byte_stuffer_recv_byte(0, 0); | ||
| 262 | } | ||
| 263 | |||
| 264 | Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { | ||
| 265 | uint8_t expected[MAX_FRAME_SIZE] = {}; | ||
| 266 | expect(validator_recv_frame, | ||
| 267 | when(size, is_equal_to(MAX_FRAME_SIZE)), | ||
| 268 | when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE)) | ||
| 269 | ); | ||
| 270 | int i; | ||
| 271 | byte_stuffer_recv_byte(0, 1); | ||
| 272 | for(i=0;i<MAX_FRAME_SIZE;i++) { | ||
| 273 | byte_stuffer_recv_byte(0, 1); | ||
| 274 | } | ||
| 275 | byte_stuffer_recv_byte(0, 0); | ||
| 276 | } | ||
| 277 | |||
| 278 | Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { | ||
| 279 | uint8_t expected[1] = {0}; | ||
| 280 | never_expect(validator_recv_frame); | ||
| 281 | int i; | ||
| 282 | byte_stuffer_recv_byte(0, 1); | ||
| 283 | for(i=0;i<MAX_FRAME_SIZE;i++) { | ||
| 284 | byte_stuffer_recv_byte(0, 1); | ||
| 285 | } | ||
| 286 | byte_stuffer_recv_byte(0, 1); | ||
| 287 | byte_stuffer_recv_byte(0, 0); | ||
| 288 | } | ||
| 289 | |||
| 290 | Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) { | ||
| 291 | uint8_t expected[1] = {1}; | ||
| 292 | expect(validator_recv_frame, | ||
| 293 | when(size, is_equal_to(1)), | ||
| 294 | when(data, is_equal_to_contents_of(expected, 1)) | ||
| 295 | ); | ||
| 296 | int i; | ||
| 297 | byte_stuffer_recv_byte(0, 1); | ||
| 298 | for(i=0;i<MAX_FRAME_SIZE;i++) { | ||
| 299 | byte_stuffer_recv_byte(0, 1); | ||
| 300 | } | ||
| 301 | byte_stuffer_recv_byte(0, 2); | ||
| 302 | byte_stuffer_recv_byte(0, 1); | ||
| 303 | byte_stuffer_recv_byte(0, 0); | ||
| 304 | } | ||
| 305 | |||
| 306 | Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) { | ||
| 307 | assert_that(sent_data_size, is_equal_to(0)); | ||
| 308 | byte_stuffer_send_frame(0, NULL, 0); | ||
| 309 | } | ||
| 310 | |||
| 311 | Ensure(ByteStuffer, send_one_byte_frame) { | ||
| 312 | uint8_t data[] = {5}; | ||
| 313 | byte_stuffer_send_frame(1, data, 1); | ||
| 314 | uint8_t expected[] = {2, 5, 0}; | ||
| 315 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 316 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 317 | } | ||
| 318 | |||
| 319 | Ensure(ByteStuffer, sends_two_byte_frame) { | ||
| 320 | uint8_t data[] = {5, 0x77}; | ||
| 321 | byte_stuffer_send_frame(0, data, 2); | ||
| 322 | uint8_t expected[] = {3, 5, 0x77, 0}; | ||
| 323 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 324 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 325 | } | ||
| 326 | |||
| 327 | Ensure(ByteStuffer, sends_one_byte_frame_with_zero) { | ||
| 328 | uint8_t data[] = {0}; | ||
| 329 | byte_stuffer_send_frame(0, data, 1); | ||
| 330 | uint8_t expected[] = {1, 1, 0}; | ||
| 331 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 332 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 333 | } | ||
| 334 | |||
| 335 | Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) { | ||
| 336 | uint8_t data[] = {0, 9}; | ||
| 337 | byte_stuffer_send_frame(1, data, 2); | ||
| 338 | uint8_t expected[] = {1, 2, 9, 0}; | ||
| 339 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 340 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 341 | } | ||
| 342 | |||
| 343 | Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) { | ||
| 344 | uint8_t data[] = {9, 0}; | ||
| 345 | byte_stuffer_send_frame(1, data, 2); | ||
| 346 | uint8_t expected[] = {2, 9, 1, 0}; | ||
| 347 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 348 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 349 | } | ||
| 350 | |||
| 351 | Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) { | ||
| 352 | uint8_t data[] = {9, 0, 0x68}; | ||
| 353 | byte_stuffer_send_frame(0, data, 3); | ||
| 354 | uint8_t expected[] = {2, 9, 2, 0x68, 0}; | ||
| 355 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 356 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 357 | } | ||
| 358 | |||
| 359 | Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) { | ||
| 360 | uint8_t data[] = {0, 0x55, 0}; | ||
| 361 | byte_stuffer_send_frame(0, data, 3); | ||
| 362 | uint8_t expected[] = {1, 2, 0x55, 1, 0}; | ||
| 363 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 364 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 365 | } | ||
| 366 | |||
| 367 | Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) { | ||
| 368 | uint8_t data[] = {0, 0, 0}; | ||
| 369 | byte_stuffer_send_frame(0, data, 3); | ||
| 370 | uint8_t expected[] = {1, 1, 1, 1, 0}; | ||
| 371 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 372 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 373 | } | ||
| 374 | |||
| 375 | Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) { | ||
| 376 | uint8_t data[254]; | ||
| 377 | int i; | ||
| 378 | for(i=0;i<254;i++) { | ||
| 379 | data[i] = i + 1; | ||
| 380 | } | ||
| 381 | byte_stuffer_send_frame(0, data, 254); | ||
| 382 | uint8_t expected[256]; | ||
| 383 | expected[0] = 0xFF; | ||
| 384 | for(i=1;i<255;i++) { | ||
| 385 | expected[i] = i; | ||
| 386 | } | ||
| 387 | expected[255] = 0; | ||
| 388 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 389 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 390 | } | ||
| 391 | |||
| 392 | Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) { | ||
| 393 | uint8_t data[255]; | ||
| 394 | int i; | ||
| 395 | for(i=0;i<255;i++) { | ||
| 396 | data[i] = i + 1; | ||
| 397 | } | ||
| 398 | byte_stuffer_send_frame(0, data, 255); | ||
| 399 | uint8_t expected[258]; | ||
| 400 | expected[0] = 0xFF; | ||
| 401 | for(i=1;i<255;i++) { | ||
| 402 | expected[i] = i; | ||
| 403 | } | ||
| 404 | expected[255] = 2; | ||
| 405 | expected[256] = 255; | ||
| 406 | expected[257] = 0; | ||
| 407 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 408 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 409 | } | ||
| 410 | |||
| 411 | Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { | ||
| 412 | uint8_t data[255]; | ||
| 413 | int i; | ||
| 414 | for(i=0;i<254;i++) { | ||
| 415 | data[i] = i + 1; | ||
| 416 | } | ||
| 417 | data[255] = 0; | ||
| 418 | byte_stuffer_send_frame(0, data, 255); | ||
| 419 | uint8_t expected[258]; | ||
| 420 | expected[0] = 0xFF; | ||
| 421 | for(i=1;i<255;i++) { | ||
| 422 | expected[i] = i; | ||
| 423 | } | ||
| 424 | expected[255] = 1; | ||
| 425 | expected[256] = 1; | ||
| 426 | expected[257] = 0; | ||
| 427 | assert_that(sent_data_size, is_equal_to(sizeof(expected))); | ||
| 428 | assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); | ||
| 429 | } | ||
| 430 | |||
| 431 | Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) { | ||
| 432 | uint8_t original_data[] = { 1, 2, 3}; | ||
| 433 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 434 | expect(validator_recv_frame, | ||
| 435 | when(size, is_equal_to(sizeof(original_data))), | ||
| 436 | when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) | ||
| 437 | ); | ||
| 438 | int i; | ||
| 439 | for(i=0;i<sent_data_size;i++) { | ||
| 440 | byte_stuffer_recv_byte(1, sent_data[i]); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) { | ||
| 445 | uint8_t original_data[] = { 1, 0, 3, 0, 0, 9}; | ||
| 446 | byte_stuffer_send_frame(1, original_data, sizeof(original_data)); | ||
| 447 | expect(validator_recv_frame, | ||
| 448 | when(size, is_equal_to(sizeof(original_data))), | ||
| 449 | when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) | ||
| 450 | ); | ||
| 451 | int i; | ||
| 452 | for(i=0;i<sent_data_size;i++) { | ||
| 453 | byte_stuffer_recv_byte(0, sent_data[i]); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) { | ||
| 458 | uint8_t original_data[254]; | ||
| 459 | int i; | ||
| 460 | for(i=0;i<254;i++) { | ||
| 461 | original_data[i] = i + 1; | ||
| 462 | } | ||
| 463 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 464 | expect(validator_recv_frame, | ||
| 465 | when(size, is_equal_to(sizeof(original_data))), | ||
| 466 | when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) | ||
| 467 | ); | ||
| 468 | for(i=0;i<sent_data_size;i++) { | ||
| 469 | byte_stuffer_recv_byte(1, sent_data[i]); | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { | ||
| 474 | uint8_t original_data[256]; | ||
| 475 | int i; | ||
| 476 | for(i=0;i<254;i++) { | ||
| 477 | original_data[i] = i + 1; | ||
| 478 | } | ||
| 479 | original_data[254] = 22; | ||
| 480 | original_data[255] = 23; | ||
| 481 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 482 | expect(validator_recv_frame, | ||
| 483 | when(size, is_equal_to(sizeof(original_data))), | ||
| 484 | when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) | ||
| 485 | ); | ||
| 486 | for(i=0;i<sent_data_size;i++) { | ||
| 487 | byte_stuffer_recv_byte(1, sent_data[i]); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { | ||
| 492 | uint8_t original_data[255]; | ||
| 493 | int i; | ||
| 494 | for(i=0;i<254;i++) { | ||
| 495 | original_data[i] = i + 1; | ||
| 496 | } | ||
| 497 | original_data[254] = 0; | ||
| 498 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 499 | expect(validator_recv_frame, | ||
| 500 | when(size, is_equal_to(sizeof(original_data))), | ||
| 501 | when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) | ||
| 502 | ); | ||
| 503 | for(i=0;i<sent_data_size;i++) { | ||
| 504 | byte_stuffer_recv_byte(1, sent_data[i]); | ||
| 505 | } | ||
| 506 | } | ||
diff --git a/quantum/serial_link/serial_link/tests/frame_router_tests.c b/quantum/serial_link/serial_link/tests/frame_router_tests.c new file mode 100644 index 000000000..6c806fa93 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/frame_router_tests.c | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <cgreen/cgreen.h> | ||
| 26 | #include <cgreen/mocks.h> | ||
| 27 | #include "serial_link/protocol/byte_stuffer.c" | ||
| 28 | #include "serial_link/protocol/frame_validator.c" | ||
| 29 | #include "serial_link/protocol/frame_router.c" | ||
| 30 | #include "serial_link/protocol/transport.h" | ||
| 31 | |||
| 32 | static uint8_t received_data[256]; | ||
| 33 | static uint16_t received_data_size; | ||
| 34 | |||
| 35 | typedef struct { | ||
| 36 | uint8_t sent_data[256]; | ||
| 37 | uint16_t sent_data_size; | ||
| 38 | } receive_buffer_t; | ||
| 39 | |||
| 40 | typedef struct { | ||
| 41 | receive_buffer_t send_buffers[2]; | ||
| 42 | } router_buffer_t; | ||
| 43 | |||
| 44 | router_buffer_t router_buffers[8]; | ||
| 45 | |||
| 46 | router_buffer_t* current_router_buffer; | ||
| 47 | |||
| 48 | |||
| 49 | Describe(FrameRouter); | ||
| 50 | BeforeEach(FrameRouter) { | ||
| 51 | init_byte_stuffer(); | ||
| 52 | memset(router_buffers, 0, sizeof(router_buffers)); | ||
| 53 | current_router_buffer = 0; | ||
| 54 | } | ||
| 55 | AfterEach(FrameRouter) {} | ||
| 56 | |||
| 57 | typedef struct { | ||
| 58 | uint32_t data; | ||
| 59 | uint8_t extra[16]; | ||
| 60 | } frame_buffer_t; | ||
| 61 | |||
| 62 | |||
| 63 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 64 | receive_buffer_t* buffer = ¤t_router_buffer->send_buffers[link]; | ||
| 65 | memcpy(buffer->sent_data + buffer->sent_data_size, data, size); | ||
| 66 | buffer->sent_data_size += size; | ||
| 67 | } | ||
| 68 | |||
| 69 | static void receive_data(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 70 | int i; | ||
| 71 | for(i=0;i<size;i++) { | ||
| 72 | byte_stuffer_recv_byte(link, data[i]); | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | static void activate_router(uint8_t num) { | ||
| 77 | current_router_buffer = router_buffers + num; | ||
| 78 | router_set_master(num==0); | ||
| 79 | } | ||
| 80 | |||
| 81 | static void simulate_transport(uint8_t from, uint8_t to) { | ||
| 82 | activate_router(to); | ||
| 83 | if (from > to) { | ||
| 84 | receive_data(DOWN_LINK, | ||
| 85 | router_buffers[from].send_buffers[UP_LINK].sent_data, | ||
| 86 | router_buffers[from].send_buffers[UP_LINK].sent_data_size); | ||
| 87 | } | ||
| 88 | else if(to > from) { | ||
| 89 | receive_data(UP_LINK, | ||
| 90 | router_buffers[from].send_buffers[DOWN_LINK].sent_data, | ||
| 91 | router_buffers[from].send_buffers[DOWN_LINK].sent_data_size); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
| 96 | mock(from, data, size); | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | Ensure(FrameRouter, master_broadcast_is_received_by_everyone) { | ||
| 101 | frame_buffer_t data; | ||
| 102 | data.data = 0xAB7055BB; | ||
| 103 | activate_router(0); | ||
| 104 | router_send_frame(0xFF, (uint8_t*)&data, 4); | ||
| 105 | assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 106 | assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 107 | |||
| 108 | expect(transport_recv_frame, | ||
| 109 | when(from, is_equal_to(0)), | ||
| 110 | when(size, is_equal_to(4)), | ||
| 111 | when(data, is_equal_to_contents_of(&data.data, 4)) | ||
| 112 | ); | ||
| 113 | simulate_transport(0, 1); | ||
| 114 | assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 115 | assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 116 | |||
| 117 | expect(transport_recv_frame, | ||
| 118 | when(from, is_equal_to(0)), | ||
| 119 | when(size, is_equal_to(4)), | ||
| 120 | when(data, is_equal_to_contents_of(&data.data, 4)) | ||
| 121 | ); | ||
| 122 | simulate_transport(1, 2); | ||
| 123 | assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 124 | assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 125 | } | ||
| 126 | |||
| 127 | Ensure(FrameRouter, master_send_is_received_by_targets) { | ||
| 128 | frame_buffer_t data; | ||
| 129 | data.data = 0xAB7055BB; | ||
| 130 | activate_router(0); | ||
| 131 | router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4); | ||
| 132 | assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 133 | assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 134 | |||
| 135 | simulate_transport(0, 1); | ||
| 136 | assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 137 | assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 138 | |||
| 139 | expect(transport_recv_frame, | ||
| 140 | when(from, is_equal_to(0)), | ||
| 141 | when(size, is_equal_to(4)), | ||
| 142 | when(data, is_equal_to_contents_of(&data.data, 4)) | ||
| 143 | ); | ||
| 144 | simulate_transport(1, 2); | ||
| 145 | assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 146 | assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 147 | |||
| 148 | expect(transport_recv_frame, | ||
| 149 | when(from, is_equal_to(0)), | ||
| 150 | when(size, is_equal_to(4)), | ||
| 151 | when(data, is_equal_to_contents_of(&data.data, 4)) | ||
| 152 | ); | ||
| 153 | simulate_transport(2, 3); | ||
| 154 | assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); | ||
| 155 | assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 156 | } | ||
| 157 | |||
| 158 | Ensure(FrameRouter, first_link_sends_to_master) { | ||
| 159 | frame_buffer_t data; | ||
| 160 | data.data = 0xAB7055BB; | ||
| 161 | activate_router(1); | ||
| 162 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 163 | assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); | ||
| 164 | assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 165 | |||
| 166 | expect(transport_recv_frame, | ||
| 167 | when(from, is_equal_to(1)), | ||
| 168 | when(size, is_equal_to(4)), | ||
| 169 | when(data, is_equal_to_contents_of(&data.data, 4)) | ||
| 170 | ); | ||
| 171 | simulate_transport(1, 0); | ||
| 172 | assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 173 | assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 174 | } | ||
| 175 | |||
| 176 | Ensure(FrameRouter, second_link_sends_to_master) { | ||
| 177 | frame_buffer_t data; | ||
| 178 | data.data = 0xAB7055BB; | ||
| 179 | activate_router(2); | ||
| 180 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 181 | assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); | ||
| 182 | assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 183 | |||
| 184 | simulate_transport(2, 1); | ||
| 185 | assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); | ||
| 186 | assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 187 | |||
| 188 | expect(transport_recv_frame, | ||
| 189 | when(from, is_equal_to(2)), | ||
| 190 | when(size, is_equal_to(4)), | ||
| 191 | when(data, is_equal_to_contents_of(&data.data, 4)) | ||
| 192 | ); | ||
| 193 | simulate_transport(1, 0); | ||
| 194 | assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 195 | assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 196 | } | ||
| 197 | |||
| 198 | Ensure(FrameRouter, master_sends_to_master_does_nothing) { | ||
| 199 | frame_buffer_t data; | ||
| 200 | data.data = 0xAB7055BB; | ||
| 201 | activate_router(0); | ||
| 202 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 203 | assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 204 | assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 205 | } | ||
| 206 | |||
| 207 | Ensure(FrameRouter, link_sends_to_other_link_does_nothing) { | ||
| 208 | frame_buffer_t data; | ||
| 209 | data.data = 0xAB7055BB; | ||
| 210 | activate_router(1); | ||
| 211 | router_send_frame(2, (uint8_t*)&data, 4); | ||
| 212 | assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 213 | assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 214 | } | ||
| 215 | |||
| 216 | Ensure(FrameRouter, master_receives_on_uplink_does_nothing) { | ||
| 217 | frame_buffer_t data; | ||
| 218 | data.data = 0xAB7055BB; | ||
| 219 | activate_router(1); | ||
| 220 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 221 | assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); | ||
| 222 | assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 223 | |||
| 224 | never_expect(transport_recv_frame); | ||
| 225 | activate_router(0); | ||
| 226 | receive_data(UP_LINK, | ||
| 227 | router_buffers[1].send_buffers[UP_LINK].sent_data, | ||
| 228 | router_buffers[1].send_buffers[UP_LINK].sent_data_size); | ||
| 229 | assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); | ||
| 230 | assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); | ||
| 231 | } | ||
diff --git a/quantum/serial_link/serial_link/tests/frame_validator_tests.c b/quantum/serial_link/serial_link/tests/frame_validator_tests.c new file mode 100644 index 000000000..d20947e2c --- /dev/null +++ b/quantum/serial_link/serial_link/tests/frame_validator_tests.c | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <cgreen/cgreen.h> | ||
| 26 | #include <cgreen/mocks.h> | ||
| 27 | #include "serial_link/protocol/frame_validator.c" | ||
| 28 | |||
| 29 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 30 | mock(data, size); | ||
| 31 | } | ||
| 32 | |||
| 33 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 34 | mock(data, size); | ||
| 35 | } | ||
| 36 | |||
| 37 | Describe(FrameValidator); | ||
| 38 | BeforeEach(FrameValidator) {} | ||
| 39 | AfterEach(FrameValidator) {} | ||
| 40 | |||
| 41 | Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) { | ||
| 42 | never_expect(route_incoming_frame); | ||
| 43 | uint8_t data[] = {1, 2}; | ||
| 44 | validator_recv_frame(0, 0, 1); | ||
| 45 | validator_recv_frame(0, data, 2); | ||
| 46 | validator_recv_frame(0, data, 3); | ||
| 47 | validator_recv_frame(0, data, 4); | ||
| 48 | } | ||
| 49 | |||
| 50 | Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) { | ||
| 51 | uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; | ||
| 52 | expect(route_incoming_frame, | ||
| 53 | when(size, is_equal_to(1)), | ||
| 54 | when(data, is_equal_to_contents_of(data, 1)) | ||
| 55 | ); | ||
| 56 | validator_recv_frame(0, data, 5); | ||
| 57 | } | ||
| 58 | |||
| 59 | Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) { | ||
| 60 | uint8_t data[] = {0x44, 0, 0, 0, 0}; | ||
| 61 | never_expect(route_incoming_frame); | ||
| 62 | validator_recv_frame(1, data, 5); | ||
| 63 | } | ||
| 64 | |||
| 65 | Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) { | ||
| 66 | uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA}; | ||
| 67 | expect(route_incoming_frame, | ||
| 68 | when(size, is_equal_to(4)), | ||
| 69 | when(data, is_equal_to_contents_of(data, 4)) | ||
| 70 | ); | ||
| 71 | validator_recv_frame(1, data, 8); | ||
| 72 | } | ||
| 73 | |||
| 74 | Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) { | ||
| 75 | uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; | ||
| 76 | expect(route_incoming_frame, | ||
| 77 | when(size, is_equal_to(5)), | ||
| 78 | when(data, is_equal_to_contents_of(data, 5)) | ||
| 79 | ); | ||
| 80 | validator_recv_frame(0, data, 9); | ||
| 81 | } | ||
| 82 | |||
| 83 | Ensure(FrameValidator, sends_one_byte_with_correct_crc) { | ||
| 84 | uint8_t original[] = {0x44, 0, 0, 0, 0}; | ||
| 85 | uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; | ||
| 86 | expect(byte_stuffer_send_frame, | ||
| 87 | when(size, is_equal_to(sizeof(expected))), | ||
| 88 | when(data, is_equal_to_contents_of(expected, sizeof(expected))) | ||
| 89 | ); | ||
| 90 | validator_send_frame(0, original, 1); | ||
| 91 | } | ||
| 92 | |||
| 93 | Ensure(FrameValidator, sends_five_bytes_with_correct_crc) { | ||
| 94 | uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0}; | ||
| 95 | uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; | ||
| 96 | expect(byte_stuffer_send_frame, | ||
| 97 | when(size, is_equal_to(sizeof(expected))), | ||
| 98 | when(data, is_equal_to_contents_of(expected, sizeof(expected))) | ||
| 99 | ); | ||
| 100 | validator_send_frame(0, original, 5); | ||
| 101 | } | ||
diff --git a/quantum/serial_link/serial_link/tests/transport_tests.c b/quantum/serial_link/serial_link/tests/transport_tests.c new file mode 100644 index 000000000..358e1b9fd --- /dev/null +++ b/quantum/serial_link/serial_link/tests/transport_tests.c | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <cgreen/cgreen.h> | ||
| 26 | #include <cgreen/mocks.h> | ||
| 27 | #include "serial_link/protocol/transport.c" | ||
| 28 | #include "serial_link/protocol/triple_buffered_object.c" | ||
| 29 | |||
| 30 | void signal_data_written(void) { | ||
| 31 | mock(); | ||
| 32 | } | ||
| 33 | |||
| 34 | static uint8_t sent_data[2048]; | ||
| 35 | static uint16_t sent_data_size; | ||
| 36 | |||
| 37 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { | ||
| 38 | mock(destination); | ||
| 39 | memcpy(sent_data + sent_data_size, data, size); | ||
| 40 | sent_data_size += size; | ||
| 41 | } | ||
| 42 | |||
| 43 | typedef struct { | ||
| 44 | uint32_t test; | ||
| 45 | } test_object1_t; | ||
| 46 | |||
| 47 | typedef struct { | ||
| 48 | uint32_t test1; | ||
| 49 | uint32_t test2; | ||
| 50 | } test_object2_t; | ||
| 51 | |||
| 52 | MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t); | ||
| 53 | MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t); | ||
| 54 | SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t); | ||
| 55 | |||
| 56 | static remote_object_t* test_remote_objects[] = { | ||
| 57 | REMOTE_OBJECT(master_to_slave), | ||
| 58 | REMOTE_OBJECT(master_to_single_slave), | ||
| 59 | REMOTE_OBJECT(slave_to_master), | ||
| 60 | }; | ||
| 61 | |||
| 62 | Describe(Transport); | ||
| 63 | BeforeEach(Transport) { | ||
| 64 | add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); | ||
| 65 | sent_data_size = 0; | ||
| 66 | } | ||
| 67 | AfterEach(Transport) {} | ||
| 68 | |||
| 69 | Ensure(Transport, write_to_local_signals_an_event) { | ||
| 70 | begin_write_master_to_slave(); | ||
| 71 | expect(signal_data_written); | ||
| 72 | end_write_master_to_slave(); | ||
| 73 | begin_write_slave_to_master(); | ||
| 74 | expect(signal_data_written); | ||
| 75 | end_write_slave_to_master(); | ||
| 76 | begin_write_master_to_single_slave(1); | ||
| 77 | expect(signal_data_written); | ||
| 78 | end_write_master_to_single_slave(1); | ||
| 79 | } | ||
| 80 | |||
| 81 | Ensure(Transport, writes_from_master_to_all_slaves) { | ||
| 82 | update_transport(); | ||
| 83 | test_object1_t* obj = begin_write_master_to_slave(); | ||
| 84 | obj->test = 5; | ||
| 85 | expect(signal_data_written); | ||
| 86 | end_write_master_to_slave(); | ||
| 87 | expect(router_send_frame, | ||
| 88 | when(destination, is_equal_to(0xFF))); | ||
| 89 | update_transport(); | ||
| 90 | transport_recv_frame(0, sent_data, sent_data_size); | ||
| 91 | test_object1_t* obj2 = read_master_to_slave(); | ||
| 92 | assert_that(obj2, is_not_equal_to(NULL)); | ||
| 93 | assert_that(obj2->test, is_equal_to(5)); | ||
| 94 | } | ||
| 95 | |||
| 96 | Ensure(Transport, writes_from_slave_to_master) { | ||
| 97 | update_transport(); | ||
| 98 | test_object1_t* obj = begin_write_slave_to_master(); | ||
| 99 | obj->test = 7; | ||
| 100 | expect(signal_data_written); | ||
| 101 | end_write_slave_to_master(); | ||
| 102 | expect(router_send_frame, | ||
| 103 | when(destination, is_equal_to(0))); | ||
| 104 | update_transport(); | ||
| 105 | transport_recv_frame(3, sent_data, sent_data_size); | ||
| 106 | test_object1_t* obj2 = read_slave_to_master(2); | ||
| 107 | assert_that(read_slave_to_master(0), is_equal_to(NULL)); | ||
| 108 | assert_that(obj2, is_not_equal_to(NULL)); | ||
| 109 | assert_that(obj2->test, is_equal_to(7)); | ||
| 110 | } | ||
| 111 | |||
| 112 | Ensure(Transport, writes_from_master_to_single_slave) { | ||
| 113 | update_transport(); | ||
| 114 | test_object1_t* obj = begin_write_master_to_single_slave(3); | ||
| 115 | obj->test = 7; | ||
| 116 | expect(signal_data_written); | ||
| 117 | end_write_master_to_single_slave(3); | ||
| 118 | expect(router_send_frame, | ||
| 119 | when(destination, is_equal_to(4))); | ||
| 120 | update_transport(); | ||
| 121 | transport_recv_frame(0, sent_data, sent_data_size); | ||
| 122 | test_object1_t* obj2 = read_master_to_single_slave(); | ||
| 123 | assert_that(obj2, is_not_equal_to(NULL)); | ||
| 124 | assert_that(obj2->test, is_equal_to(7)); | ||
| 125 | } | ||
| 126 | |||
| 127 | Ensure(Transport, ignores_object_with_invalid_id) { | ||
| 128 | update_transport(); | ||
| 129 | test_object1_t* obj = begin_write_master_to_single_slave(3); | ||
| 130 | obj->test = 7; | ||
| 131 | expect(signal_data_written); | ||
| 132 | end_write_master_to_single_slave(3); | ||
| 133 | expect(router_send_frame, | ||
| 134 | when(destination, is_equal_to(4))); | ||
| 135 | update_transport(); | ||
| 136 | sent_data[sent_data_size - 1] = 44; | ||
| 137 | transport_recv_frame(0, sent_data, sent_data_size); | ||
| 138 | test_object1_t* obj2 = read_master_to_single_slave(); | ||
| 139 | assert_that(obj2, is_equal_to(NULL)); | ||
| 140 | } | ||
| 141 | |||
| 142 | Ensure(Transport, ignores_object_with_size_too_small) { | ||
| 143 | update_transport(); | ||
| 144 | test_object1_t* obj = begin_write_master_to_slave(); | ||
| 145 | obj->test = 7; | ||
| 146 | expect(signal_data_written); | ||
| 147 | end_write_master_to_slave(); | ||
| 148 | expect(router_send_frame); | ||
| 149 | update_transport(); | ||
| 150 | sent_data[sent_data_size - 2] = 0; | ||
| 151 | transport_recv_frame(0, sent_data, sent_data_size - 1); | ||
| 152 | test_object1_t* obj2 = read_master_to_slave(); | ||
| 153 | assert_that(obj2, is_equal_to(NULL)); | ||
| 154 | } | ||
| 155 | |||
| 156 | Ensure(Transport, ignores_object_with_size_too_big) { | ||
| 157 | update_transport(); | ||
| 158 | test_object1_t* obj = begin_write_master_to_slave(); | ||
| 159 | obj->test = 7; | ||
| 160 | expect(signal_data_written); | ||
| 161 | end_write_master_to_slave(); | ||
| 162 | expect(router_send_frame); | ||
| 163 | update_transport(); | ||
| 164 | sent_data[sent_data_size + 21] = 0; | ||
| 165 | transport_recv_frame(0, sent_data, sent_data_size + 22); | ||
| 166 | test_object1_t* obj2 = read_master_to_slave(); | ||
| 167 | assert_that(obj2, is_equal_to(NULL)); | ||
| 168 | } | ||
diff --git a/quantum/serial_link/serial_link/tests/triple_buffered_object_tests.c b/quantum/serial_link/serial_link/tests/triple_buffered_object_tests.c new file mode 100644 index 000000000..6f7c82b46 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/triple_buffered_object_tests.c | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <cgreen/cgreen.h> | ||
| 26 | #include "serial_link/protocol/triple_buffered_object.c" | ||
| 27 | |||
| 28 | typedef struct { | ||
| 29 | uint8_t state; | ||
| 30 | uint32_t buffer[3]; | ||
| 31 | }test_object_t; | ||
| 32 | |||
| 33 | test_object_t test_object; | ||
| 34 | |||
| 35 | Describe(TripleBufferedObject); | ||
| 36 | BeforeEach(TripleBufferedObject) { | ||
| 37 | triple_buffer_init((triple_buffer_object_t*)&test_object); | ||
| 38 | } | ||
| 39 | AfterEach(TripleBufferedObject) {} | ||
| 40 | |||
| 41 | |||
| 42 | Ensure(TripleBufferedObject, writes_and_reads_object) { | ||
| 43 | *triple_buffer_begin_write(&test_object) = 0x3456ABCC; | ||
| 44 | triple_buffer_end_write(&test_object); | ||
| 45 | assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC)); | ||
| 46 | } | ||
| 47 | |||
| 48 | Ensure(TripleBufferedObject, does_not_read_empty) { | ||
| 49 | assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); | ||
| 50 | } | ||
| 51 | |||
| 52 | Ensure(TripleBufferedObject, writes_twice_and_reads_object) { | ||
| 53 | *triple_buffer_begin_write(&test_object) = 0x3456ABCC; | ||
| 54 | triple_buffer_end_write(&test_object); | ||
| 55 | *triple_buffer_begin_write(&test_object) = 0x44778899; | ||
| 56 | triple_buffer_end_write(&test_object); | ||
| 57 | assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899)); | ||
| 58 | } | ||
| 59 | |||
| 60 | Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) { | ||
| 61 | *triple_buffer_begin_write(&test_object) = 1; | ||
| 62 | triple_buffer_end_write(&test_object); | ||
| 63 | uint32_t* read = triple_buffer_read(&test_object); | ||
| 64 | *triple_buffer_begin_write(&test_object) = 2; | ||
| 65 | triple_buffer_end_write(&test_object); | ||
| 66 | assert_that(*read, is_equal_to(1)); | ||
| 67 | assert_that(*triple_buffer_read(&test_object), is_equal_to(2)); | ||
| 68 | assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); | ||
| 69 | } | ||
| 70 | |||
| 71 | Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { | ||
| 72 | *triple_buffer_begin_write(&test_object) = 1; | ||
| 73 | triple_buffer_end_write(&test_object); | ||
| 74 | uint32_t* read = triple_buffer_read(&test_object); | ||
| 75 | *triple_buffer_begin_write(&test_object) = 2; | ||
| 76 | triple_buffer_end_write(&test_object); | ||
| 77 | *triple_buffer_begin_write(&test_object) = 3; | ||
| 78 | triple_buffer_end_write(&test_object); | ||
| 79 | assert_that(*read, is_equal_to(1)); | ||
| 80 | assert_that(*triple_buffer_read(&test_object), is_equal_to(3)); | ||
| 81 | assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); | ||
| 82 | } | ||
diff --git a/quantum/serial_link/serial_link_tests.mk b/quantum/serial_link/serial_link_tests.mk new file mode 100644 index 000000000..e292f582a --- /dev/null +++ b/quantum/serial_link/serial_link_tests.mk | |||
| @@ -0,0 +1,34 @@ | |||
| 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 | CGREEN_LIB = $(BUILDDIR)/cgreen/build-c/src/libcgreen.a | ||
| 24 | |||
| 25 | CGREEN_DIR = "$(CURDIR)/$(SERIAL_DIR)/cgreen/cgreen" | ||
| 26 | CGREEN_BUILD_DIR = "$(CURDIR)/$(BUILDDIR)/cgreen" | ||
| 27 | export CGREEN_DIR | ||
| 28 | export CGREEN_BUILD_DIR | ||
| 29 | $(CGREEN_LIB): | ||
| 30 | @make -C $(SERIAL_DIR)/cgreen | ||
| 31 | |||
| 32 | .PHONY serialtest: | ||
| 33 | serialtest : $(CGREEN_LIB) | ||
| 34 | @make -C $(SERIAL_DIR)/serial_link/tests BUILDDIR=../../../$(BUILDDIR) \ No newline at end of file | ||
diff --git a/quantum/template/Makefile b/quantum/template/Makefile new file mode 100644 index 000000000..3f6d133c9 --- /dev/null +++ b/quantum/template/Makefile | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | |||
| 2 | |||
| 3 | # MCU name | ||
| 4 | #MCU = at90usb1287 | ||
| 5 | MCU = atmega32u4 | ||
| 6 | |||
| 7 | # Processor frequency. | ||
| 8 | # This will define a symbol, F_CPU, in all source code files equal to the | ||
| 9 | # processor frequency in Hz. You can then use this symbol in your source code to | ||
| 10 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | ||
| 11 | # automatically to create a 32-bit value in your source code. | ||
| 12 | # | ||
| 13 | # This will be an integer division of F_USB below, as it is sourced by | ||
| 14 | # F_USB after it has run through any CPU prescalers. Note that this value | ||
| 15 | # does not *change* the processor frequency - it should merely be updated to | ||
| 16 | # reflect the processor speed set externally so that the code can use accurate | ||
| 17 | # software delays. | ||
| 18 | F_CPU = 16000000 | ||
| 19 | |||
| 20 | |||
| 21 | # | ||
| 22 | # LUFA specific | ||
| 23 | # | ||
| 24 | # Target architecture (see library "Board Types" documentation). | ||
| 25 | ARCH = AVR8 | ||
| 26 | |||
| 27 | # Input clock frequency. | ||
| 28 | # This will define a symbol, F_USB, in all source code files equal to the | ||
| 29 | # input clock frequency (before any prescaling is performed) in Hz. This value may | ||
| 30 | # differ from F_CPU if prescaling is used on the latter, and is required as the | ||
| 31 | # raw input clock is fed directly to the PLL sections of the AVR for high speed | ||
| 32 | # clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' | ||
| 33 | # at the end, this will be done automatically to create a 32-bit value in your | ||
| 34 | # source code. | ||
| 35 | # | ||
| 36 | # If no clock division is performed on the input clock inside the AVR (via the | ||
| 37 | # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | ||
| 38 | F_USB = $(F_CPU) | ||
| 39 | |||
| 40 | # Interrupt driven control endpoint task(+60) | ||
| 41 | OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | ||
| 42 | |||
| 43 | |||
| 44 | # Boot Section Size in *bytes* | ||
| 45 | # Teensy halfKay 512 | ||
| 46 | # Teensy++ halfKay 1024 | ||
| 47 | # Atmel DFU loader 4096 | ||
| 48 | # LUFA bootloader 4096 | ||
| 49 | # USBaspLoader 2048 | ||
| 50 | OPT_DEFS += -DBOOTLOADER_SIZE=512 | ||
| 51 | |||
| 52 | |||
| 53 | # Build Options | ||
| 54 | # change yes to no to disable | ||
| 55 | # | ||
| 56 | BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) | ||
| 57 | MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) | ||
| 58 | EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) | ||
| 59 | CONSOLE_ENABLE ?= yes # Console for debug(+400) | ||
| 60 | COMMAND_ENABLE ?= yes # Commands for debug and configuration | ||
| 61 | # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE | ||
| 62 | SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend | ||
| 63 | # if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
| 64 | NKRO_ENABLE ?= no # USB Nkey Rollover | ||
| 65 | BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default | ||
| 66 | MIDI_ENABLE ?= no # MIDI controls | ||
| 67 | UNICODE_ENABLE ?= no # Unicode | ||
| 68 | BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID | ||
| 69 | AUDIO_ENABLE ?= no # Audio output on port C6 | ||
| 70 | |||
| 71 | ifndef QUANTUM_DIR | ||
| 72 | include ../../Makefile | ||
| 73 | endif | ||
| 74 | |||
| 75 | |||
diff --git a/quantum/template/config.h b/quantum/template/config.h new file mode 100644 index 000000000..b02f0c7eb --- /dev/null +++ b/quantum/template/config.h | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2012 Jun Wako <wakojun@gmail.com> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef CONFIG_H | ||
| 19 | #define CONFIG_H | ||
| 20 | |||
| 21 | #include "config_common.h" | ||
| 22 | |||
| 23 | /* USB Device descriptor parameter */ | ||
| 24 | #define VENDOR_ID 0xFEED | ||
| 25 | #define PRODUCT_ID 0x6060 | ||
| 26 | #define DEVICE_VER 0x0001 | ||
| 27 | #define MANUFACTURER You | ||
| 28 | #define PRODUCT %KEYBOARD% | ||
| 29 | #define DESCRIPTION A custom keyboard | ||
| 30 | |||
| 31 | /* key matrix size */ | ||
| 32 | #define MATRIX_ROWS 2 | ||
| 33 | #define MATRIX_COLS 3 | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Keyboard Matrix Assignments | ||
| 37 | * | ||
| 38 | * Change this to how you wired your keyboard | ||
| 39 | * COLS: AVR pins used for columns, left to right | ||
| 40 | * ROWS: AVR pins used for rows, top to bottom | ||
| 41 | * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode) | ||
| 42 | * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) | ||
| 43 | * | ||
| 44 | */ | ||
| 45 | #define MATRIX_ROW_PINS { D0, D5 } | ||
| 46 | #define MATRIX_COL_PINS { F1, F0, B0 } | ||
| 47 | #define UNUSED_PINS | ||
| 48 | |||
| 49 | /* COL2ROW or ROW2COL */ | ||
| 50 | #define DIODE_DIRECTION COL2ROW | ||
| 51 | |||
| 52 | // #define BACKLIGHT_PIN B7 | ||
| 53 | // #define BACKLIGHT_BREATHING | ||
| 54 | // #define BACKLIGHT_LEVELS 3 | ||
| 55 | |||
| 56 | |||
| 57 | /* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ | ||
| 58 | #define DEBOUNCING_DELAY 5 | ||
| 59 | |||
| 60 | /* define if matrix has ghost (lacks anti-ghosting diodes) */ | ||
| 61 | //#define MATRIX_HAS_GHOST | ||
| 62 | |||
| 63 | /* number of backlight levels */ | ||
| 64 | |||
| 65 | /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ | ||
| 66 | #define LOCKING_SUPPORT_ENABLE | ||
| 67 | /* Locking resynchronize hack */ | ||
| 68 | #define LOCKING_RESYNC_ENABLE | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Force NKRO | ||
| 72 | * | ||
| 73 | * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved | ||
| 74 | * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the | ||
| 75 | * makefile for this to work.) | ||
| 76 | * | ||
| 77 | * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N) | ||
| 78 | * until the next keyboard reset. | ||
| 79 | * | ||
| 80 | * NKRO may prevent your keystrokes from being detected in the BIOS, but it is | ||
| 81 | * fully operational during normal computer usage. | ||
| 82 | * | ||
| 83 | * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N) | ||
| 84 | * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by | ||
| 85 | * bootmagic, NKRO mode will always be enabled until it is toggled again during a | ||
| 86 | * power-up. | ||
| 87 | * | ||
| 88 | */ | ||
| 89 | //#define FORCE_NKRO | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Magic Key Options | ||
| 93 | * | ||
| 94 | * Magic keys are hotkey commands that allow control over firmware functions of | ||
| 95 | * the keyboard. They are best used in combination with the HID Listen program, | ||
| 96 | * found here: https://www.pjrc.com/teensy/hid_listen.html | ||
| 97 | * | ||
| 98 | * The options below allow the magic key functionality to be changed. This is | ||
| 99 | * useful if your keyboard/keypad is missing keys and you want magic key support. | ||
| 100 | * | ||
| 101 | */ | ||
| 102 | |||
| 103 | /* key combination for magic key command */ | ||
| 104 | #define IS_COMMAND() ( \ | ||
| 105 | keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ | ||
| 106 | ) | ||
| 107 | |||
| 108 | /* control how magic key switches layers */ | ||
| 109 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true | ||
| 110 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true | ||
| 111 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false | ||
| 112 | |||
| 113 | /* override magic key keymap */ | ||
| 114 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS | ||
| 115 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS | ||
| 116 | //#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM | ||
| 117 | //#define MAGIC_KEY_HELP1 H | ||
| 118 | //#define MAGIC_KEY_HELP2 SLASH | ||
| 119 | //#define MAGIC_KEY_DEBUG D | ||
| 120 | //#define MAGIC_KEY_DEBUG_MATRIX X | ||
| 121 | //#define MAGIC_KEY_DEBUG_KBD K | ||
| 122 | //#define MAGIC_KEY_DEBUG_MOUSE M | ||
| 123 | //#define MAGIC_KEY_VERSION V | ||
| 124 | //#define MAGIC_KEY_STATUS S | ||
| 125 | //#define MAGIC_KEY_CONSOLE C | ||
| 126 | //#define MAGIC_KEY_LAYER0_ALT1 ESC | ||
| 127 | //#define MAGIC_KEY_LAYER0_ALT2 GRAVE | ||
| 128 | //#define MAGIC_KEY_LAYER0 0 | ||
| 129 | //#define MAGIC_KEY_LAYER1 1 | ||
| 130 | //#define MAGIC_KEY_LAYER2 2 | ||
| 131 | //#define MAGIC_KEY_LAYER3 3 | ||
| 132 | //#define MAGIC_KEY_LAYER4 4 | ||
| 133 | //#define MAGIC_KEY_LAYER5 5 | ||
| 134 | //#define MAGIC_KEY_LAYER6 6 | ||
| 135 | //#define MAGIC_KEY_LAYER7 7 | ||
| 136 | //#define MAGIC_KEY_LAYER8 8 | ||
| 137 | //#define MAGIC_KEY_LAYER9 9 | ||
| 138 | //#define MAGIC_KEY_BOOTLOADER PAUSE | ||
| 139 | //#define MAGIC_KEY_LOCK CAPS | ||
| 140 | //#define MAGIC_KEY_EEPROM E | ||
| 141 | //#define MAGIC_KEY_NKRO N | ||
| 142 | //#define MAGIC_KEY_SLEEP_LED Z | ||
| 143 | |||
| 144 | /* | ||
| 145 | * Feature disable options | ||
| 146 | * These options are also useful to firmware size reduction. | ||
| 147 | */ | ||
| 148 | |||
| 149 | /* disable debug print */ | ||
| 150 | //#define NO_DEBUG | ||
| 151 | |||
| 152 | /* disable print */ | ||
| 153 | //#define NO_PRINT | ||
| 154 | |||
| 155 | /* disable action features */ | ||
| 156 | //#define NO_ACTION_LAYER | ||
| 157 | //#define NO_ACTION_TAPPING | ||
| 158 | //#define NO_ACTION_ONESHOT | ||
| 159 | //#define NO_ACTION_MACRO | ||
| 160 | //#define NO_ACTION_FUNCTION | ||
| 161 | |||
| 162 | #endif | ||
diff --git a/quantum/template/keymaps/default/Makefile b/quantum/template/keymaps/default/Makefile new file mode 100644 index 000000000..f4671a9d1 --- /dev/null +++ b/quantum/template/keymaps/default/Makefile | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | # Build Options | ||
| 2 | # change to "no" to disable the options, or define them in the Makefile in | ||
| 3 | # the appropriate keymap folder that will get included automatically | ||
| 4 | # | ||
| 5 | BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) | ||
| 6 | MOUSEKEY_ENABLE = yes # Mouse keys(+4700) | ||
| 7 | EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | ||
| 8 | CONSOLE_ENABLE = no # Console for debug(+400) | ||
| 9 | COMMAND_ENABLE = yes # Commands for debug and configuration | ||
| 10 | NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
| 11 | BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | ||
| 12 | MIDI_ENABLE = no # MIDI controls | ||
| 13 | AUDIO_ENABLE = no # Audio output on port C6 | ||
| 14 | UNICODE_ENABLE = no # Unicode | ||
| 15 | BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID | ||
| 16 | RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. | ||
| 17 | SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend | ||
| 18 | |||
| 19 | ifndef QUANTUM_DIR | ||
| 20 | include ../../../../Makefile | ||
| 21 | endif \ No newline at end of file | ||
diff --git a/quantum/template/keymaps/default/config.h b/quantum/template/keymaps/default/config.h new file mode 100644 index 000000000..df06a2620 --- /dev/null +++ b/quantum/template/keymaps/default/config.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef CONFIG_USER_H | ||
| 2 | #define CONFIG_USER_H | ||
| 3 | |||
| 4 | #include "../../config.h" | ||
| 5 | |||
| 6 | // place overrides here | ||
| 7 | |||
| 8 | #endif \ No newline at end of file | ||
diff --git a/quantum/template/keymaps/default/keymap.c b/quantum/template/keymaps/default/keymap.c new file mode 100644 index 000000000..e28a4723e --- /dev/null +++ b/quantum/template/keymaps/default/keymap.c | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #include "%KEYBOARD%.h" | ||
| 2 | |||
| 3 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
| 4 | [0] = KEYMAP( /* Base */ | ||
| 5 | KC_A, KC_1, KC_H, \ | ||
| 6 | KC_TAB, KC_SPC \ | ||
| 7 | ), | ||
| 8 | }; | ||
| 9 | |||
| 10 | const uint16_t PROGMEM fn_actions[] = { | ||
| 11 | |||
| 12 | }; | ||
| 13 | |||
| 14 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 15 | { | ||
| 16 | // MACRODOWN only works in this function | ||
| 17 | switch(id) { | ||
| 18 | case 0: | ||
| 19 | if (record->event.pressed) { | ||
| 20 | register_code(KC_RSFT); | ||
| 21 | } else { | ||
| 22 | unregister_code(KC_RSFT); | ||
| 23 | } | ||
| 24 | break; | ||
| 25 | } | ||
| 26 | return MACRO_NONE; | ||
| 27 | }; | ||
| 28 | |||
| 29 | |||
| 30 | void matrix_init_user(void) { | ||
| 31 | |||
| 32 | } | ||
| 33 | |||
| 34 | void matrix_scan_user(void) { | ||
| 35 | |||
| 36 | } | ||
| 37 | |||
| 38 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
| 39 | return true; | ||
| 40 | } | ||
| 41 | |||
| 42 | void led_set_user(uint8_t usb_led) { | ||
| 43 | |||
| 44 | } \ No newline at end of file | ||
diff --git a/quantum/template/keymaps/default/readme.md b/quantum/template/keymaps/default/readme.md new file mode 100644 index 000000000..21aa663d5 --- /dev/null +++ b/quantum/template/keymaps/default/readme.md | |||
| @@ -0,0 +1 @@ | |||
| # The default keymap for %KEYBOARD% \ No newline at end of file | |||
diff --git a/quantum/template/readme.md b/quantum/template/readme.md new file mode 100644 index 000000000..b2fb4dd98 --- /dev/null +++ b/quantum/template/readme.md | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | %KEYBOARD% keyboard firmware | ||
| 2 | ====================== | ||
| 3 | |||
| 4 | ## Quantum MK Firmware | ||
| 5 | |||
| 6 | For the full Quantum feature list, see [the parent readme.md](/doc/readme.md). | ||
| 7 | |||
| 8 | ## Building | ||
| 9 | |||
| 10 | Download or clone the whole firmware and navigate to the keyboards/%KEYBOARD% folder. Once your dev env is setup, you'll be able to type `make` to generate your .hex - you can then use the Teensy Loader to program your .hex file. | ||
| 11 | |||
| 12 | Depending on which keymap you would like to use, you will have to compile slightly differently. | ||
| 13 | |||
| 14 | ### Default | ||
| 15 | |||
| 16 | To build with the default keymap, simply run `make`. | ||
| 17 | |||
| 18 | ### Other Keymaps | ||
| 19 | |||
| 20 | Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create a folder with the name of your keymap in the keymaps folder, and see keymap documentation (you can find in top readme.md) and existant keymap files. | ||
| 21 | |||
| 22 | To build the firmware binary hex file with a keymap just do `make` with `keymap` option like: | ||
| 23 | |||
| 24 | ``` | ||
| 25 | $ make keymap=[default|jack|<name>] | ||
| 26 | ``` | ||
| 27 | |||
| 28 | Keymaps follow the format **__keymap.c__** and are stored in folders in the `keymaps` folder, eg `keymaps/my_keymap/` \ No newline at end of file | ||
diff --git a/quantum/template/template.c b/quantum/template/template.c new file mode 100644 index 000000000..dcc4b0a22 --- /dev/null +++ b/quantum/template/template.c | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | #include "%KEYBOARD%.h" | ||
| 2 | |||
| 3 | void matrix_init_kb(void) { | ||
| 4 | // put your keyboard start-up code here | ||
| 5 | // runs once when the firmware starts up | ||
| 6 | |||
| 7 | matrix_init_user(); | ||
| 8 | } | ||
| 9 | |||
| 10 | void matrix_scan_kb(void) { | ||
| 11 | // put your looping keyboard code here | ||
| 12 | // runs every cycle (a lot) | ||
| 13 | |||
| 14 | matrix_scan_user(); | ||
| 15 | } | ||
| 16 | |||
| 17 | bool process_record_kb(uint16_t keycode, keyrecord_t *record) { | ||
| 18 | // put your per-action keyboard code here | ||
| 19 | // runs for every action, just before processing by the firmware | ||
| 20 | |||
| 21 | return process_action_user(record); | ||
| 22 | } | ||
| 23 | |||
| 24 | void led_set_kb(uint8_t usb_led) { | ||
| 25 | // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here | ||
| 26 | |||
| 27 | led_set_user(usb_led); | ||
| 28 | } | ||
diff --git a/quantum/template/template.h b/quantum/template/template.h new file mode 100644 index 000000000..cd78a54e3 --- /dev/null +++ b/quantum/template/template.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | #ifndef %KEYBOARD_UPPERCASE%_H | ||
| 2 | #define %KEYBOARD_UPPERCASE%_H | ||
| 3 | |||
| 4 | #include "quantum.h" | ||
| 5 | |||
| 6 | // This a shortcut to help you visually see your layout. | ||
| 7 | // The following is an example using the Planck MIT layout | ||
| 8 | // The first section contains all of the arguements | ||
| 9 | // The second converts the arguments into a two-dimensional array | ||
| 10 | #define KEYMAP( \ | ||
| 11 | k00, k01, k02, \ | ||
| 12 | k10, k11 \ | ||
| 13 | ) \ | ||
| 14 | { \ | ||
| 15 | { k00, k01, k02 }, \ | ||
| 16 | { k10, KC_NO, k11 }, \ | ||
| 17 | } | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/quantum/tools/eeprom_reset.hex b/quantum/tools/eeprom_reset.hex new file mode 100644 index 000000000..a8a75389f --- /dev/null +++ b/quantum/tools/eeprom_reset.hex | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | :10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 | ||
| 2 | :10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 | ||
| 3 | :10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 | ||
| 4 | :10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 | ||
| 5 | :10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 | ||
| 6 | :10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 | ||
| 7 | :10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 | ||
| 8 | :10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 | ||
| 9 | :00000001FF | ||
diff --git a/quantum/tools/readme.md b/quantum/tools/readme.md new file mode 100644 index 000000000..5f355256d --- /dev/null +++ b/quantum/tools/readme.md | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | `eeprom_reset.hex` is to reset the eeprom on the Atmega32u4, like this: | ||
| 2 | |||
| 3 | dfu-programmer atmega32u4 erase | ||
| 4 | dfu-programmer atmega32u4 flash --eeprom eeprom_reset.hex | ||
| 5 | |||
| 6 | You'll need to reflash afterwards, because DFU requires the flash to be erased before messing with the eeprom. | ||
