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 0000000000..49b84ee0e8 --- /dev/null +++ b/quantum/analog.c @@ -0,0 +1,53 @@ +// Simple analog to digitial conversion + +#include <avr/io.h> +#include <avr/pgmspace.h> +#include <stdint.h> +#include "analog.h" + + +static uint8_t aref = (1<<REFS0); // default to AREF = Vcc + + +void analogReference(uint8_t mode) +{ + aref = mode & 0xC0; +} + + +// Arduino compatible pin input +int16_t analogRead(uint8_t pin) +{ +#if defined(__AVR_ATmega32U4__) + static const uint8_t PROGMEM pin_to_mux[] = { + 0x00, 0x01, 0x04, 0x05, 0x06, 0x07, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20}; + if (pin >= 12) return 0; + return adc_read(pgm_read_byte(pin_to_mux + pin)); +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) + if (pin >= 8) return 0; + return adc_read(pin); +#else + return 0; +#endif +} + +// Mux input +int16_t adc_read(uint8_t mux) +{ +#if defined(__AVR_AT90USB162__) + return 0; +#else + uint8_t low; + + ADCSRA = (1<<ADEN) | ADC_PRESCALER; // enable ADC + ADCSRB = (1<<ADHSM) | (mux & 0x20); // high speed mode + ADMUX = aref | (mux & 0x1F); // configure mux input + ADCSRA = (1<<ADEN) | ADC_PRESCALER | (1<<ADSC); // start the conversion + while (ADCSRA & (1<<ADSC)) ; // wait for result + low = ADCL; // must read LSB first + return (ADCH << 8) | low; // must read MSB only once! +#endif +} + + diff --git a/quantum/analog.h b/quantum/analog.h new file mode 100644 index 0000000000..9b95a93bef --- /dev/null +++ b/quantum/analog.h @@ -0,0 +1,36 @@ +#ifndef _analog_h_included__ +#define _analog_h_included__ + +#include <stdint.h> + +void analogReference(uint8_t mode); +int16_t analogRead(uint8_t pin); +int16_t adc_read(uint8_t mux); + +#define ADC_REF_POWER (1<<REFS0) +#define ADC_REF_INTERNAL ((1<<REFS1) | (1<<REFS0)) +#define ADC_REF_EXTERNAL (0) + +// These prescaler values are for high speed mode, ADHSM = 1 +#if F_CPU == 16000000L +#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS1)) +#elif F_CPU == 8000000L +#define ADC_PRESCALER ((1<<ADPS2) | (1<<ADPS0)) +#elif F_CPU == 4000000L +#define ADC_PRESCALER ((1<<ADPS2)) +#elif F_CPU == 2000000L +#define ADC_PRESCALER ((1<<ADPS1) | (1<<ADPS0)) +#elif F_CPU == 1000000L +#define ADC_PRESCALER ((1<<ADPS1)) +#else +#define ADC_PRESCALER ((1<<ADPS0)) +#endif + +// some avr-libc versions do not properly define ADHSM +#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +#if !defined(ADHSM) +#define ADHSM (7) +#endif +#endif + +#endif diff --git a/quantum/audio/audio.c b/quantum/audio/audio.c new file mode 100644 index 0000000000..ead5fbf3e9 --- /dev/null +++ b/quantum/audio/audio.c @@ -0,0 +1,477 @@ +#include <stdio.h> +#include <string.h> +//#include <math.h> +#include <avr/pgmspace.h> +#include <avr/interrupt.h> +#include <avr/io.h> +#include "print.h" +#include "audio.h" +#include "keymap.h" + +#include "eeconfig.h" + +#define CPU_PRESCALER 8 + +// ----------------------------------------------------------------------------- +// Timer Abstractions +// ----------------------------------------------------------------------------- + +// TIMSK3 - Timer/Counter #3 Interrupt Mask Register +// Turn on/off 3A interputs, stopping/enabling the ISR calls +#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) +#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) + +// TCCR3A: Timer/Counter #3 Control Register +// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 +#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); +#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); + +// Fast PWM Mode Controls +#define TIMER_3_PERIOD ICR3 +#define TIMER_3_DUTY_CYCLE OCR3A + +// ----------------------------------------------------------------------------- + + +int voices = 0; +int voice_place = 0; +float frequency = 0; +int volume = 0; +long position = 0; + +float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +bool sliding = false; + +float place = 0; + +uint8_t * sample; +uint16_t sample_length = 0; + +bool playing_notes = false; +bool playing_note = false; +float note_frequency = 0; +float note_length = 0; +uint8_t note_tempo = TEMPO_DEFAULT; +float note_timbre = TIMBRE_DEFAULT; +uint16_t note_position = 0; +float (* notes_pointer)[][2]; +uint16_t notes_count; +bool notes_repeat; +float notes_rest; +bool note_resting = false; + +uint8_t current_note = 0; +uint8_t rest_counter = 0; + +#ifdef VIBRATO_ENABLE +float vibrato_counter = 0; +float vibrato_strength = .5; +float vibrato_rate = 0.125; +#endif + +float polyphony_rate = 0; + +static bool audio_initialized = false; + +audio_config_t audio_config; + +uint16_t envelope_index = 0; + +void audio_init() +{ + + // Check EEPROM + if (!eeconfig_is_enabled()) + { + eeconfig_init(); + } + audio_config.raw = eeconfig_read_audio(); + + // Set port PC6 (OC3A and /OC4A) as output + DDRC |= _BV(PORTC6); + + DISABLE_AUDIO_COUNTER_3_ISR; + + // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers + // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 + // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) + // Clock Select (CS3n) = 0b010 = Clock / 8 + TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); + TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); + + audio_initialized = true; +} + +void stop_all_notes() +{ + if (!audio_initialized) { + audio_init(); + } + voices = 0; + + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + + playing_notes = false; + playing_note = false; + frequency = 0; + volume = 0; + + for (uint8_t i = 0; i < 8; i++) + { + frequencies[i] = 0; + volumes[i] = 0; + } +} + +void stop_note(float freq) +{ + if (playing_note) { + if (!audio_initialized) { + audio_init(); + } + for (int i = 7; i >= 0; i--) { + if (frequencies[i] == freq) { + frequencies[i] = 0; + volumes[i] = 0; + for (int j = i; (j < 7); j++) { + frequencies[j] = frequencies[j+1]; + frequencies[j+1] = 0; + volumes[j] = volumes[j+1]; + volumes[j+1] = 0; + } + break; + } + } + voices--; + if (voices < 0) + voices = 0; + if (voice_place >= voices) { + voice_place = 0; + } + if (voices == 0) { + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + frequency = 0; + volume = 0; + playing_note = false; + } + } +} + +#ifdef VIBRATO_ENABLE + +float mod(float a, int b) +{ + float r = fmod(a, b); + return r < 0 ? r + b : r; +} + +float vibrato(float average_freq) { + #ifdef VIBRATO_STRENGTH_ENABLE + float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); + #else + float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; + #endif + vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); + return vibrated_freq; +} + +#endif + +ISR(TIMER3_COMPA_vect) +{ + float freq; + + if (playing_note) { + if (voices > 0) { + if (polyphony_rate > 0) { + if (voices > 1) { + voice_place %= voices; + if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { + voice_place = (voice_place + 1) % voices; + place = 0.0; + } + } + + #ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequencies[voice_place]); + } else { + freq = frequencies[voice_place]; + } + #else + freq = frequencies[voice_place]; + #endif + } else { + if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { + frequency = frequency * pow(2, 440/frequency/12/2); + } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { + frequency = frequency * pow(2, -440/frequency/12/2); + } else { + frequency = frequencies[voices - 1]; + } + + #ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequency); + } else { + freq = frequency; + } + #else + freq = frequency; + #endif + } + + if (envelope_index < 65535) { + envelope_index++; + } + + freq = voice_envelope(freq); + + if (freq < 30.517578125) { + freq = 30.52; + } + + TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); + TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); + } + } + + if (playing_notes) { + if (note_frequency > 0) { + #ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(note_frequency); + } else { + freq = note_frequency; + } + #else + freq = note_frequency; + #endif + + if (envelope_index < 65535) { + envelope_index++; + } + freq = voice_envelope(freq); + + TIMER_3_PERIOD = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); + TIMER_3_DUTY_CYCLE = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); + } else { + TIMER_3_PERIOD = 0; + TIMER_3_DUTY_CYCLE = 0; + } + + note_position++; + bool end_of_note = false; + if (TIMER_3_PERIOD > 0) { + end_of_note = (note_position >= (note_length / TIMER_3_PERIOD * 0xFFFF)); + } else { + end_of_note = (note_position >= (note_length * 0x7FF)); + } + + if (end_of_note) { + current_note++; + if (current_note >= notes_count) { + if (notes_repeat) { + current_note = 0; + } else { + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + playing_notes = false; + return; + } + } + if (!note_resting && (notes_rest > 0)) { + note_resting = true; + note_frequency = 0; + note_length = notes_rest; + current_note--; + } else { + note_resting = false; + envelope_index = 0; + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + } + + note_position = 0; + } + } + + if (!audio_config.enable) { + playing_notes = false; + playing_note = false; + } +} + +void play_note(float freq, int vol) { + + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable && voices < 8) { + DISABLE_AUDIO_COUNTER_3_ISR; + + // Cancel notes if notes are playing + if (playing_notes) + stop_all_notes(); + + playing_note = true; + + envelope_index = 0; + + if (freq > 0) { + frequencies[voices] = freq; + volumes[voices] = vol; + voices++; + } + + ENABLE_AUDIO_COUNTER_3_ISR; + ENABLE_AUDIO_COUNTER_3_OUTPUT; + } + +} + +void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) +{ + + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable) { + + DISABLE_AUDIO_COUNTER_3_ISR; + + // Cancel note if a note is playing + if (playing_note) + stop_all_notes(); + + playing_notes = true; + + notes_pointer = np; + notes_count = n_count; + notes_repeat = n_repeat; + notes_rest = n_rest; + + place = 0; + current_note = 0; + + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + note_position = 0; + + + ENABLE_AUDIO_COUNTER_3_ISR; + ENABLE_AUDIO_COUNTER_3_OUTPUT; + } + +} + +bool is_playing_notes(void) { + return playing_notes; +} + +bool is_audio_on(void) { + return (audio_config.enable != 0); +} + +void audio_toggle(void) { + audio_config.enable ^= 1; + eeconfig_update_audio(audio_config.raw); + if (audio_config.enable) + audio_on_user(); +} + +void audio_on(void) { + audio_config.enable = 1; + eeconfig_update_audio(audio_config.raw); + audio_on_user(); +} + +void audio_off(void) { + audio_config.enable = 0; + eeconfig_update_audio(audio_config.raw); +} + +#ifdef VIBRATO_ENABLE + +// Vibrato rate functions + +void set_vibrato_rate(float rate) { + vibrato_rate = rate; +} + +void increase_vibrato_rate(float change) { + vibrato_rate *= change; +} + +void decrease_vibrato_rate(float change) { + vibrato_rate /= change; +} + +#ifdef VIBRATO_STRENGTH_ENABLE + +void set_vibrato_strength(float strength) { + vibrato_strength = strength; +} + +void increase_vibrato_strength(float change) { + vibrato_strength *= change; +} + +void decrease_vibrato_strength(float change) { + vibrato_strength /= change; +} + +#endif /* VIBRATO_STRENGTH_ENABLE */ + +#endif /* VIBRATO_ENABLE */ + +// Polyphony functions + +void set_polyphony_rate(float rate) { + polyphony_rate = rate; +} + +void enable_polyphony() { + polyphony_rate = 5; +} + +void disable_polyphony() { + polyphony_rate = 0; +} + +void increase_polyphony_rate(float change) { + polyphony_rate *= change; +} + +void decrease_polyphony_rate(float change) { + polyphony_rate /= change; +} + +// Timbre function + +void set_timbre(float timbre) { + note_timbre = timbre; +} + +// Tempo functions + +void set_tempo(uint8_t tempo) { + note_tempo = tempo; +} + +void decrease_tempo(uint8_t tempo_change) { + note_tempo += tempo_change; +} + +void increase_tempo(uint8_t tempo_change) { + if (note_tempo - tempo_change < 10) { + note_tempo = 10; + } else { + note_tempo -= tempo_change; + } +} diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h new file mode 100644 index 0000000000..47f326ea0a --- /dev/null +++ b/quantum/audio/audio.h @@ -0,0 +1,91 @@ +#ifndef AUDIO_H +#define AUDIO_H + +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include <util/delay.h> +#include "musical_notes.h" +#include "song_list.h" +#include "voices.h" +#include "quantum.h" + +// Largely untested PWM audio mode (doesn't sound as good) +// #define PWM_AUDIO + +// #define VIBRATO_ENABLE + +// Enable vibrato strength/amplitude - slows down ISR too much +// #define VIBRATO_STRENGTH_ENABLE + +typedef union { + uint8_t raw; + struct { + bool enable :1; + uint8_t level :7; + }; +} audio_config_t; + +bool is_audio_on(void); +void audio_toggle(void); +void audio_on(void); +void audio_off(void); + +// Vibrato rate functions + +#ifdef VIBRATO_ENABLE + +void set_vibrato_rate(float rate); +void increase_vibrato_rate(float change); +void decrease_vibrato_rate(float change); + +#ifdef VIBRATO_STRENGTH_ENABLE + +void set_vibrato_strength(float strength); +void increase_vibrato_strength(float change); +void decrease_vibrato_strength(float change); + +#endif + +#endif + +// Polyphony functions + +void set_polyphony_rate(float rate); +void enable_polyphony(void); +void disable_polyphony(void); +void increase_polyphony_rate(float change); +void decrease_polyphony_rate(float change); + +void set_timbre(float timbre); +void set_tempo(uint8_t tempo); + +void increase_tempo(uint8_t tempo_change); +void decrease_tempo(uint8_t tempo_change); + +void audio_init(void); + +#ifdef PWM_AUDIO +void play_sample(uint8_t * s, uint16_t l, bool r); +#endif +void play_note(float freq, int vol); +void stop_note(float freq); +void stop_all_notes(void); +void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest); + +#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), \ + 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ + 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ + 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ + 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } + +// These macros are used to allow play_notes to play an array of indeterminate +// length. This works around the limitation of C's sizeof operation on pointers. +// The global float array for the song must be used here. +#define NOTE_ARRAY_SIZE(x) ((int16_t)(sizeof(x) / (sizeof(x[0])))) +#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)); + + +bool is_playing_notes(void); + +#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 0000000000..f820eec1be --- /dev/null +++ b/quantum/audio/audio_pwm.c @@ -0,0 +1,643 @@ +#include <stdio.h> +#include <string.h> +//#include <math.h> +#include <avr/pgmspace.h> +#include <avr/interrupt.h> +#include <avr/io.h> +#include "print.h" +#include "audio.h" +#include "keymap.h" + +#include "eeconfig.h" + +#define PI 3.14159265 + +#define CPU_PRESCALER 8 + + +// Timer Abstractions + +// TIMSK3 - Timer/Counter #3 Interrupt Mask Register +// Turn on/off 3A interputs, stopping/enabling the ISR calls +#define ENABLE_AUDIO_COUNTER_3_ISR TIMSK3 |= _BV(OCIE3A) +#define DISABLE_AUDIO_COUNTER_3_ISR TIMSK3 &= ~_BV(OCIE3A) + + +// TCCR3A: Timer/Counter #3 Control Register +// Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 +#define ENABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A |= _BV(COM3A1); +#define DISABLE_AUDIO_COUNTER_3_OUTPUT TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0)); + + +#define NOTE_PERIOD ICR3 +#define NOTE_DUTY_CYCLE OCR3A + + +#ifdef PWM_AUDIO + #include "wave.h" + #define SAMPLE_DIVIDER 39 + #define SAMPLE_RATE (2000000.0/SAMPLE_DIVIDER/2048) + // Resistor value of 1/ (2 * PI * 10nF * (2000000 hertz / SAMPLE_DIVIDER / 10)) for 10nF cap + + float places[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint16_t place_int = 0; + bool repeat = true; +#endif + +void delay_us(int count) { + while(count--) { + _delay_us(1); + } +} + +int voices = 0; +int voice_place = 0; +float frequency = 0; +int volume = 0; +long position = 0; + +float frequencies[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +int volumes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +bool sliding = false; + +float place = 0; + +uint8_t * sample; +uint16_t sample_length = 0; +// float freq = 0; + +bool playing_notes = false; +bool playing_note = false; +float note_frequency = 0; +float note_length = 0; +uint8_t note_tempo = TEMPO_DEFAULT; +float note_timbre = TIMBRE_DEFAULT; +uint16_t note_position = 0; +float (* notes_pointer)[][2]; +uint16_t notes_count; +bool notes_repeat; +float notes_rest; +bool note_resting = false; + +uint8_t current_note = 0; +uint8_t rest_counter = 0; + +#ifdef VIBRATO_ENABLE +float vibrato_counter = 0; +float vibrato_strength = .5; +float vibrato_rate = 0.125; +#endif + +float polyphony_rate = 0; + +static bool audio_initialized = false; + +audio_config_t audio_config; + +uint16_t envelope_index = 0; + +void audio_init() { + + // Check EEPROM + if (!eeconfig_is_enabled()) + { + eeconfig_init(); + } + audio_config.raw = eeconfig_read_audio(); + + #ifdef PWM_AUDIO + + PLLFRQ = _BV(PDIV2); + PLLCSR = _BV(PLLE); + while(!(PLLCSR & _BV(PLOCK))); + PLLFRQ |= _BV(PLLTM0); /* PCK 48MHz */ + + /* Init a fast PWM on Timer4 */ + TCCR4A = _BV(COM4A0) | _BV(PWM4A); /* Clear OC4A on Compare Match */ + TCCR4B = _BV(CS40); /* No prescaling => f = PCK/256 = 187500Hz */ + OCR4A = 0; + + /* Enable the OC4A output */ + DDRC |= _BV(PORTC6); + + DISABLE_AUDIO_COUNTER_3_ISR; // Turn off 3A interputs + + TCCR3A = 0x0; // Options not needed + TCCR3B = _BV(CS31) | _BV(CS30) | _BV(WGM32); // 64th prescaling and CTC + OCR3A = SAMPLE_DIVIDER - 1; // Correct count/compare, related to sample playback + + #else + + // Set port PC6 (OC3A and /OC4A) as output + DDRC |= _BV(PORTC6); + + DISABLE_AUDIO_COUNTER_3_ISR; + + // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers + // Compare Output Mode (COM3An) = 0b00 = Normal port operation, OC3A disconnected from PC6 + // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14 (Period = ICR3, Duty Cycle = OCR3A) + // Clock Select (CS3n) = 0b010 = Clock / 8 + TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (1 << WGM31) | (0 << WGM30); + TCCR3B = (1 << WGM33) | (1 << WGM32) | (0 << CS32) | (1 << CS31) | (0 << CS30); + + #endif + + audio_initialized = true; +} + +void stop_all_notes() { + if (!audio_initialized) { + audio_init(); + } + voices = 0; + #ifdef PWM_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; + #else + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + #endif + + playing_notes = false; + playing_note = false; + frequency = 0; + volume = 0; + + for (uint8_t i = 0; i < 8; i++) + { + frequencies[i] = 0; + volumes[i] = 0; + } +} + +void stop_note(float freq) +{ + if (playing_note) { + if (!audio_initialized) { + audio_init(); + } + #ifdef PWM_AUDIO + freq = freq / SAMPLE_RATE; + #endif + for (int i = 7; i >= 0; i--) { + if (frequencies[i] == freq) { + frequencies[i] = 0; + volumes[i] = 0; + for (int j = i; (j < 7); j++) { + frequencies[j] = frequencies[j+1]; + frequencies[j+1] = 0; + volumes[j] = volumes[j+1]; + volumes[j+1] = 0; + } + break; + } + } + voices--; + if (voices < 0) + voices = 0; + if (voice_place >= voices) { + voice_place = 0; + } + if (voices == 0) { + #ifdef PWM_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; + #else + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + #endif + frequency = 0; + volume = 0; + playing_note = false; + } + } +} + +#ifdef VIBRATO_ENABLE + +float mod(float a, int b) +{ + float r = fmod(a, b); + return r < 0 ? r + b : r; +} + +float vibrato(float average_freq) { + #ifdef VIBRATO_STRENGTH_ENABLE + float vibrated_freq = average_freq * pow(vibrato_lut[(int)vibrato_counter], vibrato_strength); + #else + float vibrated_freq = average_freq * vibrato_lut[(int)vibrato_counter]; + #endif + vibrato_counter = mod((vibrato_counter + vibrato_rate * (1.0 + 440.0/average_freq)), VIBRATO_LUT_LENGTH); + return vibrated_freq; +} + +#endif + +ISR(TIMER3_COMPA_vect) +{ + if (playing_note) { + #ifdef PWM_AUDIO + if (voices == 1) { + // SINE + OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 2; + + // SQUARE + // if (((int)place) >= 1024){ + // OCR4A = 0xFF >> 2; + // } else { + // OCR4A = 0x00; + // } + + // SAWTOOTH + // OCR4A = (int)place / 4; + + // TRIANGLE + // if (((int)place) >= 1024) { + // OCR4A = (int)place / 2; + // } else { + // OCR4A = 2048 - (int)place / 2; + // } + + place += frequency; + + if (place >= SINE_LENGTH) + place -= SINE_LENGTH; + + } else { + int sum = 0; + for (int i = 0; i < voices; i++) { + // SINE + sum += pgm_read_byte(&sinewave[(uint16_t)places[i]]) >> 2; + + // SQUARE + // if (((int)places[i]) >= 1024){ + // sum += 0xFF >> 2; + // } else { + // sum += 0x00; + // } + + places[i] += frequencies[i]; + + if (places[i] >= SINE_LENGTH) + places[i] -= SINE_LENGTH; + } + OCR4A = sum; + } + #else + if (voices > 0) { + float freq; + if (polyphony_rate > 0) { + if (voices > 1) { + voice_place %= voices; + if (place++ > (frequencies[voice_place] / polyphony_rate / CPU_PRESCALER)) { + voice_place = (voice_place + 1) % voices; + place = 0.0; + } + } + #ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequencies[voice_place]); + } else { + #else + { + #endif + freq = frequencies[voice_place]; + } + } else { + if (frequency != 0 && frequency < frequencies[voices - 1] && frequency < frequencies[voices - 1] * pow(2, -440/frequencies[voices - 1]/12/2)) { + frequency = frequency * pow(2, 440/frequency/12/2); + } else if (frequency != 0 && frequency > frequencies[voices - 1] && frequency > frequencies[voices - 1] * pow(2, 440/frequencies[voices - 1]/12/2)) { + frequency = frequency * pow(2, -440/frequency/12/2); + } else { + frequency = frequencies[voices - 1]; + } + + + #ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(frequency); + } else { + #else + { + #endif + freq = frequency; + } + } + + if (envelope_index < 65535) { + envelope_index++; + } + freq = voice_envelope(freq); + + if (freq < 30.517578125) + freq = 30.52; + NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period + NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period + } + #endif + } + + // SAMPLE + // OCR4A = pgm_read_byte(&sample[(uint16_t)place_int]); + + // place_int++; + + // if (place_int >= sample_length) + // if (repeat) + // place_int -= sample_length; + // else + // DISABLE_AUDIO_COUNTER_3_ISR; + + + if (playing_notes) { + #ifdef PWM_AUDIO + OCR4A = pgm_read_byte(&sinewave[(uint16_t)place]) >> 0; + + place += note_frequency; + if (place >= SINE_LENGTH) + place -= SINE_LENGTH; + #else + if (note_frequency > 0) { + float freq; + + #ifdef VIBRATO_ENABLE + if (vibrato_strength > 0) { + freq = vibrato(note_frequency); + } else { + #else + { + #endif + freq = note_frequency; + } + + if (envelope_index < 65535) { + envelope_index++; + } + freq = voice_envelope(freq); + + NOTE_PERIOD = (int)(((double)F_CPU) / (freq * CPU_PRESCALER)); // Set max to the period + NOTE_DUTY_CYCLE = (int)((((double)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre); // Set compare to half the period + } else { + NOTE_PERIOD = 0; + NOTE_DUTY_CYCLE = 0; + } + #endif + + + note_position++; + bool end_of_note = false; + if (NOTE_PERIOD > 0) + end_of_note = (note_position >= (note_length / NOTE_PERIOD * 0xFFFF)); + else + end_of_note = (note_position >= (note_length * 0x7FF)); + if (end_of_note) { + current_note++; + if (current_note >= notes_count) { + if (notes_repeat) { + current_note = 0; + } else { + #ifdef PWM_AUDIO + DISABLE_AUDIO_COUNTER_3_ISR; + #else + DISABLE_AUDIO_COUNTER_3_ISR; + DISABLE_AUDIO_COUNTER_3_OUTPUT; + #endif + playing_notes = false; + return; + } + } + if (!note_resting && (notes_rest > 0)) { + note_resting = true; + note_frequency = 0; + note_length = notes_rest; + current_note--; + } else { + note_resting = false; + #ifdef PWM_AUDIO + note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; + note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100); + #else + envelope_index = 0; + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + #endif + } + note_position = 0; + } + + } + + if (!audio_config.enable) { + playing_notes = false; + playing_note = false; + } +} + +void play_note(float freq, int vol) { + + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable && voices < 8) { + DISABLE_AUDIO_COUNTER_3_ISR; + + // Cancel notes if notes are playing + if (playing_notes) + stop_all_notes(); + + playing_note = true; + + envelope_index = 0; + + #ifdef PWM_AUDIO + freq = freq / SAMPLE_RATE; + #endif + if (freq > 0) { + frequencies[voices] = freq; + volumes[voices] = vol; + voices++; + } + + #ifdef PWM_AUDIO + ENABLE_AUDIO_COUNTER_3_ISR; + #else + ENABLE_AUDIO_COUNTER_3_ISR; + ENABLE_AUDIO_COUNTER_3_OUTPUT; + #endif + } + +} + +void play_notes(float (*np)[][2], uint16_t n_count, bool n_repeat, float n_rest) +{ + + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable) { + + DISABLE_AUDIO_COUNTER_3_ISR; + + // Cancel note if a note is playing + if (playing_note) + stop_all_notes(); + + playing_notes = true; + + notes_pointer = np; + notes_count = n_count; + notes_repeat = n_repeat; + notes_rest = n_rest; + + place = 0; + current_note = 0; + + #ifdef PWM_AUDIO + note_frequency = (*notes_pointer)[current_note][0] / SAMPLE_RATE; + note_length = (*notes_pointer)[current_note][1] * (((float)note_tempo) / 100); + #else + note_frequency = (*notes_pointer)[current_note][0]; + note_length = ((*notes_pointer)[current_note][1] / 4) * (((float)note_tempo) / 100); + #endif + note_position = 0; + + + #ifdef PWM_AUDIO + ENABLE_AUDIO_COUNTER_3_ISR; + #else + ENABLE_AUDIO_COUNTER_3_ISR; + ENABLE_AUDIO_COUNTER_3_OUTPUT; + #endif + } + +} + +#ifdef PWM_AUDIO +void play_sample(uint8_t * s, uint16_t l, bool r) { + if (!audio_initialized) { + audio_init(); + } + + if (audio_config.enable) { + DISABLE_AUDIO_COUNTER_3_ISR; + stop_all_notes(); + place_int = 0; + sample = s; + sample_length = l; + repeat = r; + + ENABLE_AUDIO_COUNTER_3_ISR; + } +} +#endif + + +void audio_toggle(void) { + audio_config.enable ^= 1; + eeconfig_update_audio(audio_config.raw); +} + +void audio_on(void) { + audio_config.enable = 1; + eeconfig_update_audio(audio_config.raw); +} + +void audio_off(void) { + audio_config.enable = 0; + eeconfig_update_audio(audio_config.raw); +} + +#ifdef VIBRATO_ENABLE + +// Vibrato rate functions + +void set_vibrato_rate(float rate) { + vibrato_rate = rate; +} + +void increase_vibrato_rate(float change) { + vibrato_rate *= change; +} + +void decrease_vibrato_rate(float change) { + vibrato_rate /= change; +} + +#ifdef VIBRATO_STRENGTH_ENABLE + +void set_vibrato_strength(float strength) { + vibrato_strength = strength; +} + +void increase_vibrato_strength(float change) { + vibrato_strength *= change; +} + +void decrease_vibrato_strength(float change) { + vibrato_strength /= change; +} + +#endif /* VIBRATO_STRENGTH_ENABLE */ + +#endif /* VIBRATO_ENABLE */ + +// Polyphony functions + +void set_polyphony_rate(float rate) { + polyphony_rate = rate; +} + +void enable_polyphony() { + polyphony_rate = 5; +} + +void disable_polyphony() { + polyphony_rate = 0; +} + +void increase_polyphony_rate(float change) { + polyphony_rate *= change; +} + +void decrease_polyphony_rate(float change) { + polyphony_rate /= change; +} + +// Timbre function + +void set_timbre(float timbre) { + note_timbre = timbre; +} + +// Tempo functions + +void set_tempo(uint8_t tempo) { + note_tempo = tempo; +} + +void decrease_tempo(uint8_t tempo_change) { + note_tempo += tempo_change; +} + +void increase_tempo(uint8_t tempo_change) { + if (note_tempo - tempo_change < 10) { + note_tempo = 10; + } else { + note_tempo -= tempo_change; + } +} + + +//------------------------------------------------------------------------------ +// Override these functions in your keymap file to play different tunes on +// startup and bootloader jump +__attribute__ ((weak)) +void play_startup_tone() +{ +} + +__attribute__ ((weak)) +void play_goodbye_tone() +{ +} +//------------------------------------------------------------------------------ diff --git a/quantum/audio/luts.c b/quantum/audio/luts.c new file mode 100644 index 0000000000..9f3de9a05c --- /dev/null +++ b/quantum/audio/luts.c @@ -0,0 +1,382 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include "luts.h" + +const float vibrato_lut[VIBRATO_LUT_LENGTH] = +{ + 1.0022336811487, + 1.0042529943610, + 1.0058584256028, + 1.0068905285205, + 1.0072464122237, + 1.0068905285205, + 1.0058584256028, + 1.0042529943610, + 1.0022336811487, + 1.0000000000000, + 0.9977712970630, + 0.9957650169978, + 0.9941756956510, + 0.9931566259436, + 0.9928057204913, + 0.9931566259436, + 0.9941756956510, + 0.9957650169978, + 0.9977712970630, + 1.0000000000000, +}; + +const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH] = +{ + 0x8E0B, + 0x8C02, + 0x8A00, + 0x8805, + 0x8612, + 0x8426, + 0x8241, + 0x8063, + 0x7E8C, + 0x7CBB, + 0x7AF2, + 0x792E, + 0x7772, + 0x75BB, + 0x740B, + 0x7261, + 0x70BD, + 0x6F20, + 0x6D88, + 0x6BF6, + 0x6A69, + 0x68E3, + 0x6762, + 0x65E6, + 0x6470, + 0x6300, + 0x6194, + 0x602E, + 0x5ECD, + 0x5D71, + 0x5C1A, + 0x5AC8, + 0x597B, + 0x5833, + 0x56EF, + 0x55B0, + 0x5475, + 0x533F, + 0x520E, + 0x50E1, + 0x4FB8, + 0x4E93, + 0x4D73, + 0x4C57, + 0x4B3E, + 0x4A2A, + 0x491A, + 0x480E, + 0x4705, + 0x4601, + 0x4500, + 0x4402, + 0x4309, + 0x4213, + 0x4120, + 0x4031, + 0x3F46, + 0x3E5D, + 0x3D79, + 0x3C97, + 0x3BB9, + 0x3ADD, + 0x3A05, + 0x3930, + 0x385E, + 0x3790, + 0x36C4, + 0x35FB, + 0x3534, + 0x3471, + 0x33B1, + 0x32F3, + 0x3238, + 0x3180, + 0x30CA, + 0x3017, + 0x2F66, + 0x2EB8, + 0x2E0D, + 0x2D64, + 0x2CBD, + 0x2C19, + 0x2B77, + 0x2AD8, + 0x2A3A, + 0x299F, + 0x2907, + 0x2870, + 0x27DC, + 0x2749, + 0x26B9, + 0x262B, + 0x259F, + 0x2515, + 0x248D, + 0x2407, + 0x2382, + 0x2300, + 0x2280, + 0x2201, + 0x2184, + 0x2109, + 0x2090, + 0x2018, + 0x1FA3, + 0x1F2E, + 0x1EBC, + 0x1E4B, + 0x1DDC, + 0x1D6E, + 0x1D02, + 0x1C98, + 0x1C2F, + 0x1BC8, + 0x1B62, + 0x1AFD, + 0x1A9A, + 0x1A38, + 0x19D8, + 0x1979, + 0x191C, + 0x18C0, + 0x1865, + 0x180B, + 0x17B3, + 0x175C, + 0x1706, + 0x16B2, + 0x165E, + 0x160C, + 0x15BB, + 0x156C, + 0x151D, + 0x14CF, + 0x1483, + 0x1438, + 0x13EE, + 0x13A4, + 0x135C, + 0x1315, + 0x12CF, + 0x128A, + 0x1246, + 0x1203, + 0x11C1, + 0x1180, + 0x1140, + 0x1100, + 0x10C2, + 0x1084, + 0x1048, + 0x100C, + 0xFD1, + 0xF97, + 0xF5E, + 0xF25, + 0xEEE, + 0xEB7, + 0xE81, + 0xE4C, + 0xE17, + 0xDE4, + 0xDB1, + 0xD7E, + 0xD4D, + 0xD1C, + 0xCEC, + 0xCBC, + 0xC8E, + 0xC60, + 0xC32, + 0xC05, + 0xBD9, + 0xBAE, + 0xB83, + 0xB59, + 0xB2F, + 0xB06, + 0xADD, + 0xAB6, + 0xA8E, + 0xA67, + 0xA41, + 0xA1C, + 0x9F7, + 0x9D2, + 0x9AE, + 0x98A, + 0x967, + 0x945, + 0x923, + 0x901, + 0x8E0, + 0x8C0, + 0x8A0, + 0x880, + 0x861, + 0x842, + 0x824, + 0x806, + 0x7E8, + 0x7CB, + 0x7AF, + 0x792, + 0x777, + 0x75B, + 0x740, + 0x726, + 0x70B, + 0x6F2, + 0x6D8, + 0x6BF, + 0x6A6, + 0x68E, + 0x676, + 0x65E, + 0x647, + 0x630, + 0x619, + 0x602, + 0x5EC, + 0x5D7, + 0x5C1, + 0x5AC, + 0x597, + 0x583, + 0x56E, + 0x55B, + 0x547, + 0x533, + 0x520, + 0x50E, + 0x4FB, + 0x4E9, + 0x4D7, + 0x4C5, + 0x4B3, + 0x4A2, + 0x491, + 0x480, + 0x470, + 0x460, + 0x450, + 0x440, + 0x430, + 0x421, + 0x412, + 0x403, + 0x3F4, + 0x3E5, + 0x3D7, + 0x3C9, + 0x3BB, + 0x3AD, + 0x3A0, + 0x393, + 0x385, + 0x379, + 0x36C, + 0x35F, + 0x353, + 0x347, + 0x33B, + 0x32F, + 0x323, + 0x318, + 0x30C, + 0x301, + 0x2F6, + 0x2EB, + 0x2E0, + 0x2D6, + 0x2CB, + 0x2C1, + 0x2B7, + 0x2AD, + 0x2A3, + 0x299, + 0x290, + 0x287, + 0x27D, + 0x274, + 0x26B, + 0x262, + 0x259, + 0x251, + 0x248, + 0x240, + 0x238, + 0x230, + 0x228, + 0x220, + 0x218, + 0x210, + 0x209, + 0x201, + 0x1FA, + 0x1F2, + 0x1EB, + 0x1E4, + 0x1DD, + 0x1D6, + 0x1D0, + 0x1C9, + 0x1C2, + 0x1BC, + 0x1B6, + 0x1AF, + 0x1A9, + 0x1A3, + 0x19D, + 0x197, + 0x191, + 0x18C, + 0x186, + 0x180, + 0x17B, + 0x175, + 0x170, + 0x16B, + 0x165, + 0x160, + 0x15B, + 0x156, + 0x151, + 0x14C, + 0x148, + 0x143, + 0x13E, + 0x13A, + 0x135, + 0x131, + 0x12C, + 0x128, + 0x124, + 0x120, + 0x11C, + 0x118, + 0x114, + 0x110, + 0x10C, + 0x108, + 0x104, + 0x100, + 0xFD, + 0xF9, + 0xF5, + 0xF2, + 0xEE, +}; + diff --git a/quantum/audio/luts.h b/quantum/audio/luts.h new file mode 100644 index 0000000000..7df3078a7f --- /dev/null +++ b/quantum/audio/luts.h @@ -0,0 +1,15 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> + +#ifndef LUTS_H +#define LUTS_H + +#define VIBRATO_LUT_LENGTH 20 + +#define FREQUENCY_LUT_LENGTH 349 + +extern const float vibrato_lut[VIBRATO_LUT_LENGTH]; +extern const uint16_t frequency_lut[FREQUENCY_LUT_LENGTH]; + +#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 0000000000..b08d16a6fa --- /dev/null +++ b/quantum/audio/musical_notes.h @@ -0,0 +1,217 @@ +#ifndef MUSICAL_NOTES_H +#define MUSICAL_NOTES_H + +// Tempo Placeholder +#define TEMPO_DEFAULT 100 + + +#define SONG(notes...) { notes } + + +// Note Types +#define MUSICAL_NOTE(note, duration) {(NOTE##note), duration} +#define WHOLE_NOTE(note) MUSICAL_NOTE(note, 64) +#define HALF_NOTE(note) MUSICAL_NOTE(note, 32) +#define QUARTER_NOTE(note) MUSICAL_NOTE(note, 16) +#define EIGHTH_NOTE(note) MUSICAL_NOTE(note, 8) +#define SIXTEENTH_NOTE(note) MUSICAL_NOTE(note, 4) + +#define WHOLE_DOT_NOTE(note) MUSICAL_NOTE(note, 64+32) +#define HALF_DOT_NOTE(note) MUSICAL_NOTE(note, 32+16) +#define QUARTER_DOT_NOTE(note) MUSICAL_NOTE(note, 16+8) +#define EIGHTH_DOT_NOTE(note) MUSICAL_NOTE(note, 8+4) +#define SIXTEENTH_DOT_NOTE(note) MUSICAL_NOTE(note, 4+2) + +// Note Type Shortcuts +#define M__NOTE(note, duration) MUSICAL_NOTE(note, duration) +#define W__NOTE(n) WHOLE_NOTE(n) +#define H__NOTE(n) HALF_NOTE(n) +#define Q__NOTE(n) QUARTER_NOTE(n) +#define E__NOTE(n) EIGHTH_NOTE(n) +#define S__NOTE(n) SIXTEENTH_NOTE(n) +#define WD_NOTE(n) WHOLE_DOT_NOTE(n) +#define HD_NOTE(n) HALF_DOT_NOTE(n) +#define QD_NOTE(n) QUARTER_DOT_NOTE(n) +#define ED_NOTE(n) EIGHTH_DOT_NOTE(n) +#define SD_NOTE(n) SIXTEENTH_DOT_NOTE(n) + +// Note Styles +// Staccato makes sure there is a rest between each note. Think: TA TA TA +// Legato makes notes flow together. Think: TAAA +#define STACCATO 0.01 +#define LEGATO 0 + +// Note Timbre +// Changes how the notes sound +#define TIMBRE_12 0.125 +#define TIMBRE_25 0.250 +#define TIMBRE_50 0.500 +#define TIMBRE_75 0.750 +#define TIMBRE_DEFAULT TIMBRE_50 + + +// Notes - # = Octave + +#define NOTE_REST 0.00 + +/* These notes are currently bugged +#define NOTE_C0 16.35 +#define NOTE_CS0 17.32 +#define NOTE_D0 18.35 +#define NOTE_DS0 19.45 +#define NOTE_E0 20.60 +#define NOTE_F0 21.83 +#define NOTE_FS0 23.12 +#define NOTE_G0 24.50 +#define NOTE_GS0 25.96 +#define NOTE_A0 27.50 +#define NOTE_AS0 29.14 +#define NOTE_B0 30.87 +#define NOTE_C1 32.70 +#define NOTE_CS1 34.65 +#define NOTE_D1 36.71 +#define NOTE_DS1 38.89 +#define NOTE_E1 41.20 +#define NOTE_F1 43.65 +#define NOTE_FS1 46.25 +#define NOTE_G1 49.00 +#define NOTE_GS1 51.91 +#define NOTE_A1 55.00 +#define NOTE_AS1 58.27 +*/ + +#define NOTE_B1 61.74 +#define NOTE_C2 65.41 +#define NOTE_CS2 69.30 +#define NOTE_D2 73.42 +#define NOTE_DS2 77.78 +#define NOTE_E2 82.41 +#define NOTE_F2 87.31 +#define NOTE_FS2 92.50 +#define NOTE_G2 98.00 +#define NOTE_GS2 103.83 +#define NOTE_A2 110.00 +#define NOTE_AS2 116.54 +#define NOTE_B2 123.47 +#define NOTE_C3 130.81 +#define NOTE_CS3 138.59 +#define NOTE_D3 146.83 +#define NOTE_DS3 155.56 +#define NOTE_E3 164.81 +#define NOTE_F3 174.61 +#define NOTE_FS3 185.00 +#define NOTE_G3 196.00 +#define NOTE_GS3 207.65 +#define NOTE_A3 220.00 +#define NOTE_AS3 233.08 +#define NOTE_B3 246.94 +#define NOTE_C4 261.63 +#define NOTE_CS4 277.18 +#define NOTE_D4 293.66 +#define NOTE_DS4 311.13 +#define NOTE_E4 329.63 +#define NOTE_F4 349.23 +#define NOTE_FS4 369.99 +#define NOTE_G4 392.00 +#define NOTE_GS4 415.30 +#define NOTE_A4 440.00 +#define NOTE_AS4 466.16 +#define NOTE_B4 493.88 +#define NOTE_C5 523.25 +#define NOTE_CS5 554.37 +#define NOTE_D5 587.33 +#define NOTE_DS5 622.25 +#define NOTE_E5 659.26 +#define NOTE_F5 698.46 +#define NOTE_FS5 739.99 +#define NOTE_G5 783.99 +#define NOTE_GS5 830.61 +#define NOTE_A5 880.00 +#define NOTE_AS5 932.33 +#define NOTE_B5 987.77 +#define NOTE_C6 1046.50 +#define NOTE_CS6 1108.73 +#define NOTE_D6 1174.66 +#define NOTE_DS6 1244.51 +#define NOTE_E6 1318.51 +#define NOTE_F6 1396.91 +#define NOTE_FS6 1479.98 +#define NOTE_G6 1567.98 +#define NOTE_GS6 1661.22 +#define NOTE_A6 1760.00 +#define NOTE_AS6 1864.66 +#define NOTE_B6 1975.53 +#define NOTE_C7 2093.00 +#define NOTE_CS7 2217.46 +#define NOTE_D7 2349.32 +#define NOTE_DS7 2489.02 +#define NOTE_E7 2637.02 +#define NOTE_F7 2793.83 +#define NOTE_FS7 2959.96 +#define NOTE_G7 3135.96 +#define NOTE_GS7 3322.44 +#define NOTE_A7 3520.00 +#define NOTE_AS7 3729.31 +#define NOTE_B7 3951.07 +#define NOTE_C8 4186.01 +#define NOTE_CS8 4434.92 +#define NOTE_D8 4698.64 +#define NOTE_DS8 4978.03 +#define NOTE_E8 5274.04 +#define NOTE_F8 5587.65 +#define NOTE_FS8 5919.91 +#define NOTE_G8 6271.93 +#define NOTE_GS8 6644.88 +#define NOTE_A8 7040.00 +#define NOTE_AS8 7458.62 +#define NOTE_B8 7902.13 + +// Flat Aliases +#define NOTE_DF0 NOTE_CS0 +#define NOTE_EF0 NOTE_DS0 +#define NOTE_GF0 NOTE_FS0 +#define NOTE_AF0 NOTE_GS0 +#define NOTE_BF0 NOTE_AS0 +#define NOTE_DF1 NOTE_CS1 +#define NOTE_EF1 NOTE_DS1 +#define NOTE_GF1 NOTE_FS1 +#define NOTE_AF1 NOTE_GS1 +#define NOTE_BF1 NOTE_AS1 +#define NOTE_DF2 NOTE_CS2 +#define NOTE_EF2 NOTE_DS2 +#define NOTE_GF2 NOTE_FS2 +#define NOTE_AF2 NOTE_GS2 +#define NOTE_BF2 NOTE_AS2 +#define NOTE_DF3 NOTE_CS3 +#define NOTE_EF3 NOTE_DS3 +#define NOTE_GF3 NOTE_FS3 +#define NOTE_AF3 NOTE_GS3 +#define NOTE_BF3 NOTE_AS3 +#define NOTE_DF4 NOTE_CS4 +#define NOTE_EF4 NOTE_DS4 +#define NOTE_GF4 NOTE_FS4 +#define NOTE_AF4 NOTE_GS4 +#define NOTE_BF4 NOTE_AS4 +#define NOTE_DF5 NOTE_CS5 +#define NOTE_EF5 NOTE_DS5 +#define NOTE_GF5 NOTE_FS5 +#define NOTE_AF5 NOTE_GS5 +#define NOTE_BF5 NOTE_AS5 +#define NOTE_DF6 NOTE_CS6 +#define NOTE_EF6 NOTE_DS6 +#define NOTE_GF6 NOTE_FS6 +#define NOTE_AF6 NOTE_GS6 +#define NOTE_BF6 NOTE_AS6 +#define NOTE_DF7 NOTE_CS7 +#define NOTE_EF7 NOTE_DS7 +#define NOTE_GF7 NOTE_FS7 +#define NOTE_AF7 NOTE_GS7 +#define NOTE_BF7 NOTE_AS7 +#define NOTE_DF8 NOTE_CS8 +#define NOTE_EF8 NOTE_DS8 +#define NOTE_GF8 NOTE_FS8 +#define NOTE_AF8 NOTE_GS8 +#define NOTE_BF8 NOTE_AS8 + + +#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 0000000000..fc6fcdeef1 --- /dev/null +++ b/quantum/audio/song_list.h @@ -0,0 +1,117 @@ +#include "musical_notes.h" + +#ifndef SONG_LIST_H +#define SONG_LIST_H + +#define ODE_TO_JOY \ + Q__NOTE(_E4), Q__NOTE(_E4), Q__NOTE(_F4), Q__NOTE(_G4), \ + Q__NOTE(_G4), Q__NOTE(_F4), Q__NOTE(_E4), Q__NOTE(_D4), \ + Q__NOTE(_C4), Q__NOTE(_C4), Q__NOTE(_D4), Q__NOTE(_E4), \ + QD_NOTE(_E4), E__NOTE(_D4), H__NOTE(_D4), + +#define ROCK_A_BYE_BABY \ + QD_NOTE(_B4), E__NOTE(_D4), Q__NOTE(_B5), \ + H__NOTE(_A5), Q__NOTE(_G5), \ + QD_NOTE(_B4), E__NOTE(_D5), Q__NOTE(_G5), \ + H__NOTE(_FS5), + +#define CLOSE_ENCOUNTERS_5_NOTE \ + Q__NOTE(_D5), \ + Q__NOTE(_E5), \ + Q__NOTE(_C5), \ + Q__NOTE(_C4), \ + Q__NOTE(_G4), + +#define DOE_A_DEER \ + QD_NOTE(_C4), E__NOTE(_D4), \ + QD_NOTE(_E4), E__NOTE(_C4), \ + Q__NOTE(_E4), Q__NOTE(_C4), \ + Q__NOTE(_E4), + +#define GOODBYE_SOUND \ + E__NOTE(_E7), \ + E__NOTE(_A6), \ + ED_NOTE(_E6), + +#define STARTUP_SOUND \ + ED_NOTE(_E7 ), \ + E__NOTE(_CS7), \ + E__NOTE(_E6 ), \ + E__NOTE(_A6 ), \ + M__NOTE(_CS7, 20), + +#define QWERTY_SOUND \ + E__NOTE(_GS6 ), \ + E__NOTE(_A6 ), \ + S__NOTE(_REST), \ + Q__NOTE(_E7 ), + +#define COLEMAK_SOUND \ + E__NOTE(_GS6 ), \ + E__NOTE(_A6 ), \ + S__NOTE(_REST), \ + ED_NOTE(_E7 ), \ + S__NOTE(_REST), \ + ED_NOTE(_GS7 ), + +#define DVORAK_SOUND \ + E__NOTE(_GS6 ), \ + E__NOTE(_A6 ), \ + S__NOTE(_REST), \ + E__NOTE(_E7 ), \ + S__NOTE(_REST), \ + E__NOTE(_FS7 ), \ + S__NOTE(_REST), \ + E__NOTE(_E7 ), + +#define PLOVER_SOUND \ + E__NOTE(_GS6 ), \ + E__NOTE(_A6 ), \ + S__NOTE(_REST), \ + ED_NOTE(_E7 ), \ + S__NOTE(_REST), \ + ED_NOTE(_A7 ), + +#define PLOVER_GOODBYE_SOUND \ + E__NOTE(_GS6 ), \ + E__NOTE(_A6 ), \ + S__NOTE(_REST), \ + ED_NOTE(_A7 ), \ + S__NOTE(_REST), \ + ED_NOTE(_E7 ), + +#define MUSIC_SCALE_SOUND \ + E__NOTE(_A5 ), \ + E__NOTE(_B5 ), \ + E__NOTE(_CS6), \ + E__NOTE(_D6 ), \ + E__NOTE(_E6 ), \ + E__NOTE(_FS6), \ + E__NOTE(_GS6), \ + E__NOTE(_A6 ), + +#define CAPS_LOCK_ON_SOUND \ + E__NOTE(_A3), \ + E__NOTE(_B3), + +#define CAPS_LOCK_OFF_SOUND \ + E__NOTE(_B3), \ + E__NOTE(_A3), + +#define SCROLL_LOCK_ON_SOUND \ + E__NOTE(_D4), \ + E__NOTE(_E4), + +#define SCROLL_LOCK_OFF_SOUND \ + E__NOTE(_E4), \ + E__NOTE(_D4), + +#define NUM_LOCK_ON_SOUND \ + E__NOTE(_D5), \ + E__NOTE(_E5), + +#define NUM_LOCK_OFF_SOUND \ + E__NOTE(_E5), \ + E__NOTE(_D5), + +#endif diff --git a/quantum/audio/voices.c b/quantum/audio/voices.c new file mode 100644 index 0000000000..6d4172a06c --- /dev/null +++ b/quantum/audio/voices.c @@ -0,0 +1,165 @@ +#include "voices.h" +#include "audio.h" +#include "stdlib.h" + +// these are imported from audio.c +extern uint16_t envelope_index; +extern float note_timbre; +extern float polyphony_rate; + +voice_type voice = default_voice; + +void set_voice(voice_type v) { + voice = v; +} + +void voice_iterate() { + voice = (voice + 1) % number_of_voices; +} + +void voice_deiterate() { + voice = (voice - 1) % number_of_voices; +} + +float voice_envelope(float frequency) { + // envelope_index ranges from 0 to 0xFFFF, which is preserved at 880.0 Hz + uint16_t compensated_index = (uint16_t)((float)envelope_index * (880.0 / frequency)); + + switch (voice) { + case default_voice: + note_timbre = TIMBRE_50; + polyphony_rate = 0; + break; + + case butts_fader: + polyphony_rate = 0; + switch (compensated_index) { + case 0 ... 9: + frequency = frequency / 4; + note_timbre = TIMBRE_12; + break; + + case 10 ... 19: + frequency = frequency / 2; + note_timbre = TIMBRE_12; + break; + + case 20 ... 200: + note_timbre = .125 - pow(((float)compensated_index - 20) / (200 - 20), 2)*.125; + break; + + default: + note_timbre = 0; + break; + } + break; + + // case octave_crunch: + // polyphony_rate = 0; + // switch (compensated_index) { + // case 0 ... 9: + // case 20 ... 24: + // case 30 ... 32: + // frequency = frequency / 2; + // note_timbre = TIMBRE_12; + // break; + + // case 10 ... 19: + // case 25 ... 29: + // case 33 ... 35: + // frequency = frequency * 2; + // note_timbre = TIMBRE_12; + // break; + + // default: + // note_timbre = TIMBRE_12; + // break; + // } + // break; + + case duty_osc: + // This slows the loop down a substantial amount, so higher notes may freeze + polyphony_rate = 0; + switch (compensated_index) { + default: + #define OCS_SPEED 10 + #define OCS_AMP .25 + // sine wave is slow + // note_timbre = (sin((float)compensated_index/10000*OCS_SPEED) * OCS_AMP / 2) + .5; + // triangle wave is a bit faster + note_timbre = (float)abs((compensated_index*OCS_SPEED % 3000) - 1500) * ( OCS_AMP / 1500 ) + (1 - OCS_AMP) / 2; + break; + } + break; + + case duty_octave_down: + polyphony_rate = 0; + note_timbre = (envelope_index % 2) * .125 + .375 * 2; + if ((envelope_index % 4) == 0) + note_timbre = 0.5; + if ((envelope_index % 8) == 0) + note_timbre = 0; + break; + case delayed_vibrato: + polyphony_rate = 0; + note_timbre = TIMBRE_50; + #define VOICE_VIBRATO_DELAY 150 + #define VOICE_VIBRATO_SPEED 50 + switch (compensated_index) { + case 0 ... VOICE_VIBRATO_DELAY: + break; + default: + frequency = frequency * vibrato_lut[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; + break; + } + break; + // case delayed_vibrato_octave: + // polyphony_rate = 0; + // if ((envelope_index % 2) == 1) { + // note_timbre = 0.55; + // } else { + // note_timbre = 0.45; + // } + // #define VOICE_VIBRATO_DELAY 150 + // #define VOICE_VIBRATO_SPEED 50 + // switch (compensated_index) { + // case 0 ... VOICE_VIBRATO_DELAY: + // break; + // default: + // frequency = frequency * VIBRATO_LUT[(int)fmod((((float)compensated_index - (VOICE_VIBRATO_DELAY + 1))/1000*VOICE_VIBRATO_SPEED), VIBRATO_LUT_LENGTH)]; + // break; + // } + // break; + // case duty_fifth_down: + // note_timbre = 0.5; + // if ((envelope_index % 3) == 0) + // note_timbre = 0.75; + // break; + // case duty_fourth_down: + // note_timbre = 0.0; + // if ((envelope_index % 12) == 0) + // note_timbre = 0.75; + // if (((envelope_index % 12) % 4) != 1) + // note_timbre = 0.75; + // break; + // case duty_third_down: + // note_timbre = 0.5; + // if ((envelope_index % 5) == 0) + // note_timbre = 0.75; + // break; + // case duty_fifth_third_down: + // note_timbre = 0.5; + // if ((envelope_index % 5) == 0) + // note_timbre = 0.75; + // if ((envelope_index % 3) == 0) + // note_timbre = 0.25; + // break; + + default: + break; + } + + return frequency; +} + + diff --git a/quantum/audio/voices.h b/quantum/audio/voices.h new file mode 100644 index 0000000000..b2495b23b5 --- /dev/null +++ b/quantum/audio/voices.h @@ -0,0 +1,31 @@ +#include <stdint.h> +#include <stdbool.h> +#include <avr/io.h> +#include <util/delay.h> +#include "luts.h" + +#ifndef VOICES_H +#define VOICES_H + +float voice_envelope(float frequency); + +typedef enum { + default_voice, + butts_fader, + octave_crunch, + duty_osc, + duty_octave_down, + delayed_vibrato, + // delayed_vibrato_octave, + // duty_fifth_down, + // duty_fourth_down, + // duty_third_down, + // duty_fifth_third_down, + number_of_voices // important that this is last +} voice_type; + +void set_voice(voice_type v); +void voice_iterate(void); +void voice_deiterate(void); + +#endif
\ No newline at end of file diff --git a/quantum/audio/wave.h b/quantum/audio/wave.h new file mode 100644 index 0000000000..6ebc348519 --- /dev/null +++ b/quantum/audio/wave.h @@ -0,0 +1,265 @@ +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> + +#define SINE_LENGTH 2048 + +const uint8_t sinewave[] PROGMEM= //2048 values +{ +0x80,0x80,0x80,0x81,0x81,0x81,0x82,0x82, +0x83,0x83,0x83,0x84,0x84,0x85,0x85,0x85, +0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88, +0x89,0x89,0x8a,0x8a,0x8a,0x8b,0x8b,0x8c, +0x8c,0x8c,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f, +0x8f,0x8f,0x90,0x90,0x91,0x91,0x91,0x92, +0x92,0x93,0x93,0x93,0x94,0x94,0x95,0x95, +0x95,0x96,0x96,0x96,0x97,0x97,0x98,0x98, +0x98,0x99,0x99,0x9a,0x9a,0x9a,0x9b,0x9b, +0x9b,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e, +0x9e,0x9f,0x9f,0xa0,0xa0,0xa0,0xa1,0xa1, +0xa2,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4, +0xa5,0xa5,0xa5,0xa6,0xa6,0xa6,0xa7,0xa7, +0xa7,0xa8,0xa8,0xa9,0xa9,0xa9,0xaa,0xaa, +0xaa,0xab,0xab,0xac,0xac,0xac,0xad,0xad, +0xad,0xae,0xae,0xae,0xaf,0xaf,0xb0,0xb0, +0xb0,0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb3, +0xb3,0xb4,0xb4,0xb4,0xb5,0xb5,0xb5,0xb6, +0xb6,0xb6,0xb7,0xb7,0xb7,0xb8,0xb8,0xb8, +0xb9,0xb9,0xba,0xba,0xba,0xbb,0xbb,0xbb, +0xbc,0xbc,0xbc,0xbd,0xbd,0xbd,0xbe,0xbe, +0xbe,0xbf,0xbf,0xbf,0xc0,0xc0,0xc0,0xc1, +0xc1,0xc1,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3, +0xc4,0xc4,0xc4,0xc5,0xc5,0xc5,0xc6,0xc6, +0xc6,0xc7,0xc7,0xc7,0xc8,0xc8,0xc8,0xc9, +0xc9,0xc9,0xca,0xca,0xca,0xcb,0xcb,0xcb, +0xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce, +0xce,0xce,0xcf,0xcf,0xcf,0xcf,0xd0,0xd0, +0xd0,0xd1,0xd1,0xd1,0xd2,0xd2,0xd2,0xd2, +0xd3,0xd3,0xd3,0xd4,0xd4,0xd4,0xd5,0xd5, +0xd5,0xd5,0xd6,0xd6,0xd6,0xd7,0xd7,0xd7, +0xd7,0xd8,0xd8,0xd8,0xd9,0xd9,0xd9,0xd9, +0xda,0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdc, +0xdc,0xdc,0xdc,0xdd,0xdd,0xdd,0xdd,0xde, +0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xe0, +0xe0,0xe0,0xe1,0xe1,0xe1,0xe1,0xe2,0xe2, +0xe2,0xe2,0xe3,0xe3,0xe3,0xe3,0xe4,0xe4, +0xe4,0xe4,0xe4,0xe5,0xe5,0xe5,0xe5,0xe6, +0xe6,0xe6,0xe6,0xe7,0xe7,0xe7,0xe7,0xe8, +0xe8,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xe9, +0xea,0xea,0xea,0xea,0xea,0xeb,0xeb,0xeb, +0xeb,0xeb,0xec,0xec,0xec,0xec,0xec,0xed, +0xed,0xed,0xed,0xed,0xee,0xee,0xee,0xee, +0xee,0xef,0xef,0xef,0xef,0xef,0xf0,0xf0, +0xf0,0xf0,0xf0,0xf0,0xf1,0xf1,0xf1,0xf1, +0xf1,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2,0xf3, +0xf3,0xf3,0xf3,0xf3,0xf3,0xf4,0xf4,0xf4, +0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5, +0xf5,0xf5,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6, +0xf6,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, +0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, +0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, +0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, +0xfa,0xfa,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb, +0xfb,0xfb,0xfb,0xfb,0xfc,0xfc,0xfc,0xfc, +0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, +0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, +0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfe,0xfe, +0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, +0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, +0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe, +0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, +0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe, +0xfe,0xfe,0xfe,0xfd,0xfd,0xfd,0xfd,0xfd, +0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd,0xfd, +0xfd,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc, +0xfc,0xfc,0xfc,0xfc,0xfc,0xfb,0xfb,0xfb, +0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfb,0xfa, +0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa,0xfa, +0xfa,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9,0xf9, +0xf9,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8,0xf8, +0xf8,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7, +0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf5, +0xf5,0xf5,0xf5,0xf5,0xf5,0xf5,0xf4,0xf4, +0xf4,0xf4,0xf4,0xf4,0xf3,0xf3,0xf3,0xf3, +0xf3,0xf3,0xf2,0xf2,0xf2,0xf2,0xf2,0xf2, +0xf1,0xf1,0xf1,0xf1,0xf1,0xf0,0xf0,0xf0, +0xf0,0xf0,0xf0,0xef,0xef,0xef,0xef,0xef, +0xee,0xee,0xee,0xee,0xee,0xed,0xed,0xed, +0xed,0xed,0xec,0xec,0xec,0xec,0xec,0xeb, +0xeb,0xeb,0xeb,0xeb,0xea,0xea,0xea,0xea, +0xea,0xe9,0xe9,0xe9,0xe9,0xe8,0xe8,0xe8, +0xe8,0xe8,0xe7,0xe7,0xe7,0xe7,0xe6,0xe6, +0xe6,0xe6,0xe5,0xe5,0xe5,0xe5,0xe4,0xe4, +0xe4,0xe4,0xe4,0xe3,0xe3,0xe3,0xe3,0xe2, +0xe2,0xe2,0xe2,0xe1,0xe1,0xe1,0xe1,0xe0, +0xe0,0xe0,0xe0,0xdf,0xdf,0xdf,0xde,0xde, +0xde,0xde,0xdd,0xdd,0xdd,0xdd,0xdc,0xdc, +0xdc,0xdc,0xdb,0xdb,0xdb,0xda,0xda,0xda, +0xda,0xd9,0xd9,0xd9,0xd9,0xd8,0xd8,0xd8, +0xd7,0xd7,0xd7,0xd7,0xd6,0xd6,0xd6,0xd5, +0xd5,0xd5,0xd5,0xd4,0xd4,0xd4,0xd3,0xd3, +0xd3,0xd2,0xd2,0xd2,0xd2,0xd1,0xd1,0xd1, +0xd0,0xd0,0xd0,0xcf,0xcf,0xcf,0xcf,0xce, +0xce,0xce,0xcd,0xcd,0xcd,0xcc,0xcc,0xcc, +0xcb,0xcb,0xcb,0xcb,0xca,0xca,0xca,0xc9, +0xc9,0xc9,0xc8,0xc8,0xc8,0xc7,0xc7,0xc7, +0xc6,0xc6,0xc6,0xc5,0xc5,0xc5,0xc4,0xc4, +0xc4,0xc3,0xc3,0xc3,0xc2,0xc2,0xc2,0xc1, +0xc1,0xc1,0xc0,0xc0,0xc0,0xbf,0xbf,0xbf, +0xbe,0xbe,0xbe,0xbd,0xbd,0xbd,0xbc,0xbc, +0xbc,0xbb,0xbb,0xbb,0xba,0xba,0xba,0xb9, +0xb9,0xb8,0xb8,0xb8,0xb7,0xb7,0xb7,0xb6, +0xb6,0xb6,0xb5,0xb5,0xb5,0xb4,0xb4,0xb4, +0xb3,0xb3,0xb2,0xb2,0xb2,0xb1,0xb1,0xb1, +0xb0,0xb0,0xb0,0xaf,0xaf,0xae,0xae,0xae, +0xad,0xad,0xad,0xac,0xac,0xac,0xab,0xab, +0xaa,0xaa,0xaa,0xa9,0xa9,0xa9,0xa8,0xa8, +0xa7,0xa7,0xa7,0xa6,0xa6,0xa6,0xa5,0xa5, +0xa5,0xa4,0xa4,0xa3,0xa3,0xa3,0xa2,0xa2, +0xa2,0xa1,0xa1,0xa0,0xa0,0xa0,0x9f,0x9f, +0x9e,0x9e,0x9e,0x9d,0x9d,0x9d,0x9c,0x9c, +0x9b,0x9b,0x9b,0x9a,0x9a,0x9a,0x99,0x99, +0x98,0x98,0x98,0x97,0x97,0x96,0x96,0x96, +0x95,0x95,0x95,0x94,0x94,0x93,0x93,0x93, +0x92,0x92,0x91,0x91,0x91,0x90,0x90,0x8f, +0x8f,0x8f,0x8e,0x8e,0x8e,0x8d,0x8d,0x8c, +0x8c,0x8c,0x8b,0x8b,0x8a,0x8a,0x8a,0x89, +0x89,0x88,0x88,0x88,0x87,0x87,0x87,0x86, +0x86,0x85,0x85,0x85,0x84,0x84,0x83,0x83, +0x83,0x82,0x82,0x81,0x81,0x81,0x80,0x80, +0x80,0x7f,0x7f,0x7e,0x7e,0x7e,0x7d,0x7d, +0x7c,0x7c,0x7c,0x7b,0x7b,0x7a,0x7a,0x7a, +0x79,0x79,0x78,0x78,0x78,0x77,0x77,0x77, +0x76,0x76,0x75,0x75,0x75,0x74,0x74,0x73, +0x73,0x73,0x72,0x72,0x71,0x71,0x71,0x70, +0x70,0x70,0x6f,0x6f,0x6e,0x6e,0x6e,0x6d, +0x6d,0x6c,0x6c,0x6c,0x6b,0x6b,0x6a,0x6a, +0x6a,0x69,0x69,0x69,0x68,0x68,0x67,0x67, +0x67,0x66,0x66,0x65,0x65,0x65,0x64,0x64, +0x64,0x63,0x63,0x62,0x62,0x62,0x61,0x61, +0x61,0x60,0x60,0x5f,0x5f,0x5f,0x5e,0x5e, +0x5d,0x5d,0x5d,0x5c,0x5c,0x5c,0x5b,0x5b, +0x5a,0x5a,0x5a,0x59,0x59,0x59,0x58,0x58, +0x58,0x57,0x57,0x56,0x56,0x56,0x55,0x55, +0x55,0x54,0x54,0x53,0x53,0x53,0x52,0x52, +0x52,0x51,0x51,0x51,0x50,0x50,0x4f,0x4f, +0x4f,0x4e,0x4e,0x4e,0x4d,0x4d,0x4d,0x4c, +0x4c,0x4b,0x4b,0x4b,0x4a,0x4a,0x4a,0x49, +0x49,0x49,0x48,0x48,0x48,0x47,0x47,0x47, +0x46,0x46,0x45,0x45,0x45,0x44,0x44,0x44, +0x43,0x43,0x43,0x42,0x42,0x42,0x41,0x41, +0x41,0x40,0x40,0x40,0x3f,0x3f,0x3f,0x3e, +0x3e,0x3e,0x3d,0x3d,0x3d,0x3c,0x3c,0x3c, +0x3b,0x3b,0x3b,0x3a,0x3a,0x3a,0x39,0x39, +0x39,0x38,0x38,0x38,0x37,0x37,0x37,0x36, +0x36,0x36,0x35,0x35,0x35,0x34,0x34,0x34, +0x34,0x33,0x33,0x33,0x32,0x32,0x32,0x31, +0x31,0x31,0x30,0x30,0x30,0x30,0x2f,0x2f, +0x2f,0x2e,0x2e,0x2e,0x2d,0x2d,0x2d,0x2d, +0x2c,0x2c,0x2c,0x2b,0x2b,0x2b,0x2a,0x2a, +0x2a,0x2a,0x29,0x29,0x29,0x28,0x28,0x28, +0x28,0x27,0x27,0x27,0x26,0x26,0x26,0x26, +0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x23, +0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x21, +0x21,0x21,0x21,0x20,0x20,0x20,0x1f,0x1f, +0x1f,0x1f,0x1e,0x1e,0x1e,0x1e,0x1d,0x1d, +0x1d,0x1d,0x1c,0x1c,0x1c,0x1c,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x19, +0x19,0x19,0x19,0x18,0x18,0x18,0x18,0x17, +0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16, +0x15,0x15,0x15,0x15,0x15,0x14,0x14,0x14, +0x14,0x14,0x13,0x13,0x13,0x13,0x13,0x12, +0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11, +0x11,0x10,0x10,0x10,0x10,0x10,0xf,0xf, +0xf,0xf,0xf,0xf,0xe,0xe,0xe,0xe, +0xe,0xd,0xd,0xd,0xd,0xd,0xd,0xc, +0xc,0xc,0xc,0xc,0xc,0xb,0xb,0xb, +0xb,0xb,0xb,0xa,0xa,0xa,0xa,0xa, +0xa,0xa,0x9,0x9,0x9,0x9,0x9,0x9, +0x9,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x7,0x7,0x7,0x7,0x7,0x7,0x7,0x7, +0x6,0x6,0x6,0x6,0x6,0x6,0x6,0x6, +0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5, +0x5,0x5,0x4,0x4,0x4,0x4,0x4,0x4, +0x4,0x4,0x4,0x4,0x3,0x3,0x3,0x3, +0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3, +0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, +0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x1, +0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, +0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, +0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1, +0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, +0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, +0x1,0x1,0x1,0x2,0x2,0x2,0x2,0x2, +0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2, +0x2,0x3,0x3,0x3,0x3,0x3,0x3,0x3, +0x3,0x3,0x3,0x3,0x3,0x4,0x4,0x4, +0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x5, +0x5,0x5,0x5,0x5,0x5,0x5,0x5,0x5, +0x5,0x6,0x6,0x6,0x6,0x6,0x6,0x6, +0x6,0x7,0x7,0x7,0x7,0x7,0x7,0x7, +0x7,0x8,0x8,0x8,0x8,0x8,0x8,0x8, +0x9,0x9,0x9,0x9,0x9,0x9,0x9,0xa, +0xa,0xa,0xa,0xa,0xa,0xa,0xb,0xb, +0xb,0xb,0xb,0xb,0xc,0xc,0xc,0xc, +0xc,0xc,0xd,0xd,0xd,0xd,0xd,0xd, +0xe,0xe,0xe,0xe,0xe,0xf,0xf,0xf, +0xf,0xf,0xf,0x10,0x10,0x10,0x10,0x10, +0x11,0x11,0x11,0x11,0x11,0x12,0x12,0x12, +0x12,0x12,0x13,0x13,0x13,0x13,0x13,0x14, +0x14,0x14,0x14,0x14,0x15,0x15,0x15,0x15, +0x15,0x16,0x16,0x16,0x16,0x17,0x17,0x17, +0x17,0x17,0x18,0x18,0x18,0x18,0x19,0x19, +0x19,0x19,0x1a,0x1a,0x1a,0x1a,0x1b,0x1b, +0x1b,0x1b,0x1b,0x1c,0x1c,0x1c,0x1c,0x1d, +0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x1e,0x1f, +0x1f,0x1f,0x1f,0x20,0x20,0x20,0x21,0x21, +0x21,0x21,0x22,0x22,0x22,0x22,0x23,0x23, +0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x25, +0x25,0x26,0x26,0x26,0x26,0x27,0x27,0x27, +0x28,0x28,0x28,0x28,0x29,0x29,0x29,0x2a, +0x2a,0x2a,0x2a,0x2b,0x2b,0x2b,0x2c,0x2c, +0x2c,0x2d,0x2d,0x2d,0x2d,0x2e,0x2e,0x2e, +0x2f,0x2f,0x2f,0x30,0x30,0x30,0x30,0x31, +0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x33, +0x34,0x34,0x34,0x34,0x35,0x35,0x35,0x36, +0x36,0x36,0x37,0x37,0x37,0x38,0x38,0x38, +0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b, +0x3b,0x3c,0x3c,0x3c,0x3d,0x3d,0x3d,0x3e, +0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40, +0x41,0x41,0x41,0x42,0x42,0x42,0x43,0x43, +0x43,0x44,0x44,0x44,0x45,0x45,0x45,0x46, +0x46,0x47,0x47,0x47,0x48,0x48,0x48,0x49, +0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,0x4b, +0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4e, +0x4f,0x4f,0x4f,0x50,0x50,0x51,0x51,0x51, +0x52,0x52,0x52,0x53,0x53,0x53,0x54,0x54, +0x55,0x55,0x55,0x56,0x56,0x56,0x57,0x57, +0x58,0x58,0x58,0x59,0x59,0x59,0x5a,0x5a, +0x5a,0x5b,0x5b,0x5c,0x5c,0x5c,0x5d,0x5d, +0x5d,0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60, +0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, +0x64,0x64,0x64,0x65,0x65,0x65,0x66,0x66, +0x67,0x67,0x67,0x68,0x68,0x69,0x69,0x69, +0x6a,0x6a,0x6a,0x6b,0x6b,0x6c,0x6c,0x6c, +0x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x70, +0x70,0x70,0x71,0x71,0x71,0x72,0x72,0x73, +0x73,0x73,0x74,0x74,0x75,0x75,0x75,0x76, +0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79, +0x79,0x7a,0x7a,0x7a,0x7b,0x7b,0x7c,0x7c, +0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f +};
\ No newline at end of file diff --git a/quantum/config_common.h b/quantum/config_common.h new file mode 100644 index 0000000000..09a4fe7010 --- /dev/null +++ b/quantum/config_common.h @@ -0,0 +1,119 @@ +#ifndef CONFIG_DEFINITIONS_H +#define CONFIG_DEFINITIONS_H + +/* diode directions */ +#define COL2ROW 0 +#define ROW2COL 1 +/* I/O pins */ +#define B0 0x30 +#define B1 0x31 +#define B2 0x32 +#define B3 0x33 +#define B4 0x34 +#define B5 0x35 +#define B6 0x36 +#define B7 0x37 +#define C0 0x60 +#define C1 0x61 +#define C2 0x62 +#define C3 0x63 +#define C4 0x64 +#define C5 0x65 +#define C6 0x66 +#define C7 0x67 +#define D0 0x90 +#define D1 0x91 +#define D2 0x92 +#define D3 0x93 +#define D4 0x94 +#define D5 0x95 +#define D6 0x96 +#define D7 0x97 +#define E0 0xC0 +#define E1 0xC1 +#define E2 0xC2 +#define E3 0xC3 +#define E4 0xC4 +#define E5 0xC5 +#define E6 0xC6 +#define E7 0xC7 +#define F0 0xF0 +#define F1 0xF1 +#define F2 0xF2 +#define F3 0xF3 +#define F4 0xF4 +#define F5 0xF5 +#define F6 0xF6 +#define F7 0xF7 + +/* USART configuration */ +#ifdef BLUETOOTH_ENABLE +# ifdef __AVR_ATmega32U4__ +# define SERIAL_UART_BAUD 9600 +# define SERIAL_UART_DATA UDR1 +# define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1) +# define SERIAL_UART_RXD_VECT USART1_RX_vect +# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1)) +# define SERIAL_UART_INIT() do { \ + /* baud rate */ \ + UBRR1L = SERIAL_UART_UBRR; \ + /* baud rate */ \ + UBRR1H = SERIAL_UART_UBRR >> 8; \ + /* enable TX */ \ + UCSR1B = _BV(TXEN1); \ + /* 8-bit data */ \ + UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \ + sei(); \ + } while(0) +# else +# error "USART configuration is needed." +#endif + +// I'm fairly sure these aren't needed, but oh well - Jack + +/* + * PS/2 Interrupt configuration + */ +#ifdef PS2_USE_INT +/* uses INT1 for clock line(ATMega32U4) */ +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 1 + +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 0 + +#define PS2_INT_INIT() do { \ + EICRA |= ((1<<ISC11) | \ + (0<<ISC10)); \ +} while (0) +#define PS2_INT_ON() do { \ + EIMSK |= (1<<INT1); \ +} while (0) +#define PS2_INT_OFF() do { \ + EIMSK &= ~(1<<INT1); \ +} while (0) +#define PS2_INT_VECT INT1_vect +#endif + +/* + * PS/2 Busywait configuration + */ +#ifdef PS2_USE_BUSYWAIT +#define PS2_CLOCK_PORT PORTD +#define PS2_CLOCK_PIN PIND +#define PS2_CLOCK_DDR DDRD +#define PS2_CLOCK_BIT 1 + +#define PS2_DATA_PORT PORTD +#define PS2_DATA_PIN PIND +#define PS2_DATA_DDR DDRD +#define PS2_DATA_BIT 0 +#endif + +#endif + +#endif diff --git a/quantum/keycode_config.c b/quantum/keycode_config.c new file mode 100644 index 0000000000..6d90781a17 --- /dev/null +++ b/quantum/keycode_config.c @@ -0,0 +1,74 @@ +#include "keycode_config.h" + +extern keymap_config_t keymap_config; + +uint16_t keycode_config(uint16_t keycode) { + + switch (keycode) { + case KC_CAPSLOCK: + case KC_LOCKING_CAPS: + if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) { + return KC_LCTL; + } + return keycode; + case KC_LCTL: + if (keymap_config.swap_control_capslock) { + return KC_CAPSLOCK; + } + return KC_LCTL; + case KC_LALT: + if (keymap_config.swap_lalt_lgui) { + if (keymap_config.no_gui) { + return KC_NO; + } + return KC_LGUI; + } + return KC_LALT; + case KC_LGUI: + if (keymap_config.swap_lalt_lgui) { + return KC_LALT; + } + if (keymap_config.no_gui) { + return KC_NO; + } + return KC_LGUI; + case KC_RALT: + if (keymap_config.swap_ralt_rgui) { + if (keymap_config.no_gui) { + return KC_NO; + } + return KC_RGUI; + } + return KC_RALT; + case KC_RGUI: + if (keymap_config.swap_ralt_rgui) { + return KC_RALT; + } + if (keymap_config.no_gui) { + return KC_NO; + } + return KC_RGUI; + case KC_GRAVE: + if (keymap_config.swap_grave_esc) { + return KC_ESC; + } + return KC_GRAVE; + case KC_ESC: + if (keymap_config.swap_grave_esc) { + return KC_GRAVE; + } + return KC_ESC; + case KC_BSLASH: + if (keymap_config.swap_backslash_backspace) { + return KC_BSPACE; + } + return KC_BSLASH; + case KC_BSPACE: + if (keymap_config.swap_backslash_backspace) { + return KC_BSLASH; + } + return KC_BSPACE; + default: + return keycode; + } +}
\ No newline at end of file diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h new file mode 100644 index 0000000000..6216eefc90 --- /dev/null +++ b/quantum/keycode_config.h @@ -0,0 +1,21 @@ +#include "eeconfig.h" +#include "keycode.h" + +uint16_t keycode_config(uint16_t keycode); + +/* NOTE: Not portable. Bit field order depends on implementation */ +typedef union { + uint16_t raw; + struct { + bool swap_control_capslock:1; + bool capslock_to_control:1; + bool swap_lalt_lgui:1; + bool swap_ralt_rgui:1; + bool no_gui:1; + bool swap_grave_esc:1; + bool swap_backslash_backspace:1; + bool nkro:1; + }; +} keymap_config_t; + +extern keymap_config_t keymap_config; diff --git a/quantum/keymap.h b/quantum/keymap.h new file mode 100644 index 0000000000..73f99f8211 --- /dev/null +++ b/quantum/keymap.h @@ -0,0 +1,328 @@ +/* +Copyright 2012,2013 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef KEYMAP_H +#define KEYMAP_H + +#include <stdint.h> +#include <stdbool.h> +#include "action.h" +#if defined(__AVR__) +#include <avr/pgmspace.h> +#endif +#include "keycode.h" +#include "action_macro.h" +#include "report.h" +#include "host.h" +// #include "print.h" +#include "debug.h" +#include "keycode_config.h" + +// ChibiOS uses RESET in its FlagStatus enumeration +// Therefore define it as QK_RESET here, to avoid name collision +#if defined(PROTOCOL_CHIBIOS) +#define RESET QK_RESET +#endif + +/* translates key to keycode */ +uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); + +extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; +extern const uint16_t fn_actions[]; + +enum quantum_keycodes { + // Ranges used in shortucuts - not to be used directly + QK_TMK = 0x0000, + QK_TMK_MAX = 0x00FF, + QK_MODS = 0x0100, + QK_LCTL = 0x0100, + QK_LSFT = 0x0200, + QK_LALT = 0x0400, + QK_LGUI = 0x0800, + QK_RCTL = 0x1100, + QK_RSFT = 0x1200, + QK_RALT = 0x1400, + QK_RGUI = 0x1800, + QK_MODS_MAX = 0x1FFF, + QK_FUNCTION = 0x2000, + QK_FUNCTION_MAX = 0x2FFF, + QK_MACRO = 0x3000, + QK_MACRO_MAX = 0x3FFF, + QK_LAYER_TAP = 0x4000, + QK_LAYER_TAP_MAX = 0x4FFF, + QK_TO = 0x5000, + QK_TO_MAX = 0x50FF, + QK_MOMENTARY = 0x5100, + QK_MOMENTARY_MAX = 0x51FF, + QK_DEF_LAYER = 0x5200, + QK_DEF_LAYER_MAX = 0x52FF, + QK_TOGGLE_LAYER = 0x5300, + QK_TOGGLE_LAYER_MAX = 0x53FF, + QK_ONE_SHOT_LAYER = 0x5400, + QK_ONE_SHOT_LAYER_MAX = 0x54FF, + QK_ONE_SHOT_MOD = 0x5500, + QK_ONE_SHOT_MOD_MAX = 0x55FF, +#ifndef DISABLE_CHORDING + QK_CHORDING = 0x5600, + QK_CHORDING_MAX = 0x56FF, +#endif + QK_MOD_TAP = 0x6000, + QK_MOD_TAP_MAX = 0x6FFF, + QK_TAP_DANCE = 0x7100, + QK_TAP_DANCE_MAX = 0x71FF, +#ifdef UNICODE_ENABLE + QK_UNICODE = 0x8000, + QK_UNICODE_MAX = 0xFFFF, +#endif + + // Loose keycodes - to be used directly + + RESET = 0x7000, + DEBUG, + MAGIC_SWAP_CONTROL_CAPSLOCK, + MAGIC_CAPSLOCK_TO_CONTROL, + MAGIC_SWAP_LALT_LGUI, + MAGIC_SWAP_RALT_RGUI, + MAGIC_NO_GUI, + MAGIC_SWAP_GRAVE_ESC, + MAGIC_SWAP_BACKSLASH_BACKSPACE, + MAGIC_HOST_NKRO, + MAGIC_SWAP_ALT_GUI, + MAGIC_UNSWAP_CONTROL_CAPSLOCK, + MAGIC_UNCAPSLOCK_TO_CONTROL, + MAGIC_UNSWAP_LALT_LGUI, + MAGIC_UNSWAP_RALT_RGUI, + MAGIC_UNNO_GUI, + MAGIC_UNSWAP_GRAVE_ESC, + MAGIC_UNSWAP_BACKSLASH_BACKSPACE, + MAGIC_UNHOST_NKRO, + MAGIC_UNSWAP_ALT_GUI, + + // Leader key +#ifndef DISABLE_LEADER + KC_LEAD, +#endif + + // Audio on/off/toggle + AU_ON, + AU_OFF, + AU_TOG, + + // Music mode on/off/toggle + MU_ON, + MU_OFF, + MU_TOG, + + // Music voice iterate + MUV_IN, + MUV_DE, + + // Midi mode on/off + MIDI_ON, + MIDI_OFF, + + // Backlight functionality + BL_0, + BL_1, + BL_2, + BL_3, + BL_4, + BL_5, + BL_6, + BL_7, + BL_8, + BL_9, + BL_10, + BL_11, + BL_12, + BL_13, + BL_14, + BL_15, + BL_DEC, + BL_INC, + BL_TOGG, + BL_STEP, + + // Left shift, open paren + KC_LSPO, + + // Right shift, close paren + KC_RSPC, + + // always leave at the end + SAFE_RANGE +}; + +// Ability to use mods in layouts +#define LCTL(kc) (kc | QK_LCTL) +#define LSFT(kc) (kc | QK_LSFT) +#define LALT(kc) (kc | QK_LALT) +#define LGUI(kc) (kc | QK_LGUI) +#define RCTL(kc) (kc | QK_RCTL) +#define RSFT(kc) (kc | QK_RSFT) +#define RALT(kc) (kc | QK_RALT) +#define RGUI(kc) (kc | QK_RGUI) + +#define HYPR(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT | QK_LGUI) +#define MEH(kc) (kc | QK_LCTL | QK_LSFT | QK_LALT) +#define LCAG(kc) (kc | QK_LCTL | QK_LALT | QK_LGUI) + +#define MOD_HYPR 0xf +#define MOD_MEH 0x7 + + +// Aliases for shifted symbols +// Each key has a 4-letter code, and some have longer aliases too. +// While the long aliases are descriptive, the 4-letter codes +// make for nicer grid layouts (everything lines up), and are +// the preferred style for Quantum. +#define KC_TILD LSFT(KC_GRV) // ~ +#define KC_TILDE KC_TILD + +#define KC_EXLM LSFT(KC_1) // ! +#define KC_EXCLAIM KC_EXLM + +#define KC_AT LSFT(KC_2) // @ + +#define KC_HASH LSFT(KC_3) // # + +#define KC_DLR LSFT(KC_4) // $ +#define KC_DOLLAR KC_DLR + +#define KC_PERC LSFT(KC_5) // % +#define KC_PERCENT KC_PERC + +#define KC_CIRC LSFT(KC_6) // ^ +#define KC_CIRCUMFLEX KC_CIRC + +#define KC_AMPR LSFT(KC_7) // & +#define KC_AMPERSAND KC_AMPR + +#define KC_ASTR LSFT(KC_8) // * +#define KC_ASTERISK KC_ASTR + +#define KC_LPRN LSFT(KC_9) // ( +#define KC_LEFT_PAREN KC_LPRN + +#define KC_RPRN LSFT(KC_0) // ) +#define KC_RIGHT_PAREN KC_RPRN + +#define KC_UNDS LSFT(KC_MINS) // _ +#define KC_UNDERSCORE KC_UNDS + +#define KC_PLUS LSFT(KC_EQL) // + + +#define KC_LCBR LSFT(KC_LBRC) // { +#define KC_LEFT_CURLY_BRACE KC_LCBR + +#define KC_RCBR LSFT(KC_RBRC) // } +#define KC_RIGHT_CURLY_BRACE KC_RCBR + +#define KC_LABK LSFT(KC_COMM) // < +#define KC_LEFT_ANGLE_BRACKET KC_LABK + +#define KC_RABK LSFT(KC_DOT) // > +#define KC_RIGHT_ANGLE_BRACKET KC_RABK + +#define KC_COLN LSFT(KC_SCLN) // : +#define KC_COLON KC_COLN + +#define KC_PIPE LSFT(KC_BSLS) // | + +#define KC_LT LSFT(KC_COMM) // < + +#define KC_GT LSFT(KC_DOT) // > + +#define KC_QUES LSFT(KC_SLSH) // ? +#define KC_QUESTION KC_QUES + +#define KC_DQT LSFT(KC_QUOT) // " +#define KC_DOUBLE_QUOTE KC_DQT +#define KC_DQUO KC_DQT + +#define KC_DELT KC_DELETE // Del key (four letter code) + +// Alias for function layers than expand past FN31 +#define FUNC(kc) (kc | QK_FUNCTION) + +// Aliases +#define S(kc) LSFT(kc) +#define F(kc) FUNC(kc) + +#define M(kc) (kc | QK_MACRO) + +#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE) + +// L-ayer, T-ap - 256 keycode max, 16 layer max +#define LT(layer, kc) (kc | QK_LAYER_TAP | ((layer & 0xF) << 8)) + +#define AG_SWAP MAGIC_SWAP_ALT_GUI +#define AG_NORM MAGIC_UNSWAP_ALT_GUI + +#define BL_ON BL_9 +#define BL_OFF BL_0 + +#define MI_ON MIDI_ON +#define MI_OFF MIDI_OFF + +// GOTO layer - 16 layers max +// when: +// ON_PRESS = 1 +// ON_RELEASE = 2 +// Unless you have a good reason not to do so, prefer ON_PRESS (1) as your default. +#define TO(layer, when) (layer | QK_TO | (when << 0x4)) + +// Momentary switch layer - 256 layer max +#define MO(layer) (layer | QK_MOMENTARY) + +// Set default layer - 256 layer max +#define DF(layer) (layer | QK_DEF_LAYER) + +// Toggle to layer - 256 layer max +#define TG(layer) (layer | QK_TOGGLE_LAYER) + +// One-shot layer - 256 layer max +#define OSL(layer) (layer | QK_ONE_SHOT_LAYER) + +// One-shot mod +#define OSM(layer) (layer | QK_ONE_SHOT_MOD) + +// M-od, T-ap - 256 keycode max +#define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8)) +#define CTL_T(kc) MT(MOD_LCTL, kc) +#define SFT_T(kc) MT(MOD_LSFT, kc) +#define ALT_T(kc) MT(MOD_LALT, kc) +#define GUI_T(kc) MT(MOD_LGUI, kc) +#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal +#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 +#define LCAG_T(kc) MT((MOD_LCTL | MOD_LALT | MOD_LGUI), kc) // Left control alt and gui +#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/ + +// Dedicated keycode versions for Hyper and Meh, if you want to use them as standalone keys rather than mod-tap +#define KC_HYPR HYPR(KC_NO) +#define KC_MEH MEH(KC_NO) + +#ifdef UNICODE_ENABLE + // For sending unicode codes. + // You may not send codes over 7FFF -- this supports most of UTF8. + // To have a key that sends out Œ, go UC(0x0152) + #define UNICODE(n) (n | QK_UNICODE) + #define UC(n) UNICODE(n) +#endif + + +#endif diff --git a/quantum/keymap_common.c b/quantum/keymap_common.c new file mode 100644 index 0000000000..76872ac592 --- /dev/null +++ b/quantum/keymap_common.c @@ -0,0 +1,171 @@ +/* +Copyright 2012,2013 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "keymap.h" +#include "report.h" +#include "keycode.h" +#include "action_layer.h" +#if defined(__AVR__) +#include <util/delay.h> +#include <stdio.h> +#endif +#include "action.h" +#include "action_macro.h" +#include "debug.h" +#include "backlight.h" +#include "quantum.h" + +#ifdef MIDI_ENABLE + #include "keymap_midi.h" +#endif + +extern keymap_config_t keymap_config; + +#include <inttypes.h> + +/* converts key to action */ +action_t action_for_key(uint8_t layer, keypos_t key) +{ + // 16bit keycodes - important + uint16_t keycode = keymap_key_to_keycode(layer, key); + + // keycode remapping + keycode = keycode_config(keycode); + + action_t action; + uint8_t action_layer, when, mod; + // The arm-none-eabi compiler generates out of bounds warnings when using the fn_actions directly for some reason + const uint16_t* actions = fn_actions; + + switch (keycode) { + case KC_FN0 ... KC_FN31: + action.code = pgm_read_word(&actions[FN_INDEX(keycode)]); + break; + case KC_A ... KC_EXSEL: + case KC_LCTRL ... KC_RGUI: + action.code = ACTION_KEY(keycode); + break; + case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE: + action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode)); + break; + case KC_AUDIO_MUTE ... KC_WWW_FAVORITES: + action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode)); + break; + case KC_MS_UP ... KC_MS_ACCEL2: + action.code = ACTION_MOUSEKEY(keycode); + break; + case KC_TRNS: + action.code = ACTION_TRANSPARENT; + break; + case QK_MODS ... QK_MODS_MAX: ; + // Has a modifier + // Split it up + action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key + break; + case QK_FUNCTION ... QK_FUNCTION_MAX: ; + // Is a shortcut for function action_layer, pull last 12bits + // This means we have 4,096 FN macros at our disposal + action.code = pgm_read_word(&actions[(int)keycode & 0xFFF]); + break; + case QK_MACRO ... QK_MACRO_MAX: + action.code = ACTION_MACRO(keycode & 0xFF); + break; + case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: + action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); + break; + case QK_TO ... QK_TO_MAX: ; + // Layer set "GOTO" + when = (keycode >> 0x4) & 0x3; + action_layer = keycode & 0xF; + action.code = ACTION_LAYER_SET(action_layer, when); + break; + case QK_MOMENTARY ... QK_MOMENTARY_MAX: ; + // Momentary action_layer + action_layer = keycode & 0xFF; + action.code = ACTION_LAYER_MOMENTARY(action_layer); + break; + case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: ; + // Set default action_layer + action_layer = keycode & 0xFF; + action.code = ACTION_DEFAULT_LAYER_SET(action_layer); + break; + case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: ; + // Set toggle + action_layer = keycode & 0xFF; + action.code = ACTION_LAYER_TOGGLE(action_layer); + break; + case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: ; + // OSL(action_layer) - One-shot action_layer + action_layer = keycode & 0xFF; + action.code = ACTION_LAYER_ONESHOT(action_layer); + break; + case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: ; + // OSM(mod) - One-shot mod + mod = keycode & 0xFF; + action.code = ACTION_MODS_ONESHOT(mod); + break; + case QK_MOD_TAP ... QK_MOD_TAP_MAX: + action.code = ACTION_MODS_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF); + break; + #ifdef BACKLIGHT_ENABLE + case BL_0 ... BL_15: + action.code = ACTION_BACKLIGHT_LEVEL(keycode - BL_0); + break; + case BL_DEC: + action.code = ACTION_BACKLIGHT_DECREASE(); + break; + case BL_INC: + action.code = ACTION_BACKLIGHT_INCREASE(); + break; + case BL_TOGG: + action.code = ACTION_BACKLIGHT_TOGGLE(); + break; + case BL_STEP: + action.code = ACTION_BACKLIGHT_STEP(); + break; + #endif + default: + action.code = ACTION_NO; + break; + } + return action; +} + +__attribute__ ((weak)) +const uint16_t PROGMEM fn_actions[] = { + +}; + +/* Macro */ +__attribute__ ((weak)) +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + return MACRO_NONE; +} + +/* Function */ +__attribute__ ((weak)) +void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) +{ +} + +/* translates key to keycode */ +uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) +{ + // Read entire word (16bits) + return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]); +} diff --git a/quantum/keymap_extras/keymap_bepo.h b/quantum/keymap_extras/keymap_bepo.h new file mode 100644 index 0000000000..4c30960547 --- /dev/null +++ b/quantum/keymap_extras/keymap_bepo.h @@ -0,0 +1,311 @@ +/* Keymap macros for the French BÉPO layout - http://bepo.fr */ +#ifndef KEYMAP_BEPO_H +#define KEYMAP_BEPO_H + +#include "keymap.h" + +// Alt gr +#ifndef ALTGR +#define ALTGR(kc) RALT(kc) +#endif +#ifndef ALGR +#define ALGR(kc) ALTGR(kc) +#endif +#define BP_ALGR KC_RALT + +// Normal characters +// First row (on usual keyboards) +#define BP_DOLLAR KC_GRAVE // $ +#define BP_DLR BP_DOLLAR +#define BP_DOUBLE_QUOTE KC_1 // " +#define BP_DQOT BP_DOUBLE_QUOTE +#define BP_LEFT_GUILLEMET KC_2 // « +#define BP_LGIL BP_LEFT_GUILLEMET +#define BP_RIGHT_GUILLEMET KC_3 // » +#define BP_RGIL BP_RIGHT_GUILLEMET +#define BP_LEFT_PAREN KC_4 // ( +#define BP_LPRN BP_LEFT_PAREN +#define BP_RIGHT_PAREN KC_5 // ) +#define BP_RPRN BP_RIGHT_PAREN +#define BP_AT KC_6 // @ +#define BP_PLUS KC_7 // + +#define BP_MINUS KC_8 // - +#define BP_MINS BP_MINUS +#define BP_SLASH KC_9 // / +#define BP_SLSH BP_SLASH +#define BP_ASTERISK KC_0 // * +#define BP_ASTR BP_ASTERISK +#define BP_EQUAL KC_MINUS // = +#define BP_EQL BP_EQUAL +#define BP_PERCENT KC_EQUAL // % +#define BP_PERC BP_PERCENT + +// Second row +#define BP_B KC_Q +#define BP_E_ACUTE KC_W // é +#define BP_ECUT BP_E_ACUTE +#define BP_P KC_E +#define BP_O KC_R +#define BP_E_GRAVE KC_T // è +#define BP_EGRV BP_E_GRAVE +#define BP_DEAD_CIRCUMFLEX KC_Y // dead ^ +#define BP_DCRC BP_DEAD_CIRCUMFLEX +#define BP_V KC_U +#define BP_D KC_I +#define BP_L KC_O +#define BP_J KC_P +#define BP_Z KC_LBRACKET +#define BP_W KC_RBRACKET + +// Third row +#define BP_A KC_A +#define BP_U KC_S +#define BP_I KC_D +#define BP_E KC_F +#define BP_COMMA KC_G // , +#define BP_COMM BP_COMMA +#define BP_C KC_H +#define BP_T KC_J +#define BP_S KC_K +#define BP_R KC_L +#define BP_N KC_SCOLON +#define BP_M KC_QUOTE +#define BP_C_CEDILLA KC_BSLASH // ç +#define BP_CCED BP_C_CEDILLA + +// Fourth row +#define BP_E_CIRCUMFLEX KC_NONUS_BSLASH // ê +#define BP_ECRC BP_E_CIRCUMFLEX +#define BP_A_GRAVE KC_Z // à +#define BP_AGRV BP_A_GRAVE +#define BP_Y KC_X +#define BP_X KC_C +#define BP_DOT KC_V // . +#define BP_K KC_B +#define BP_APOSTROPHE KC_N +#define BP_APOS BP_APOSTROPHE // ' +#define BP_Q KC_M +#define BP_G KC_COMMA +#define BP_H KC_DOT +#define BP_F KC_SLASH + +// Shifted characters +// First row +#define BP_HASH LSFT(BP_DOLLAR) // # +#define BP_1 LSFT(KC_1) +#define BP_2 LSFT(KC_2) +#define BP_3 LSFT(KC_3) +#define BP_4 LSFT(KC_4) +#define BP_5 LSFT(KC_5) +#define BP_6 LSFT(KC_6) +#define BP_7 LSFT(KC_7) +#define BP_8 LSFT(KC_8) +#define BP_9 LSFT(KC_9) +#define BP_0 LSFT(KC_0) +#define BP_DEGREE LSFT(BP_EQUAL) // ° +#define BP_DEGR BP_DEGREE +#define BP_GRAVE LSFT(BP_PERCENT) // ` +#define BP_GRV BP_GRAVE + +// Second row +#define BP_EXCLAIM LSFT(BP_DEAD_CIRCUMFLEX) // ! +#define BP_EXLM BP_EXCLAIM + +// Third row +#define BP_SCOLON LSFT(BP_COMMA) // ; +#define BP_SCLN BP_SCOLON + +// Fourth row +#define BP_COLON LSFT(BP_DOT) // : +#define BP_COLN BP_COLON +#define BP_QUESTION LSFT(BP_QUOTE) // ? +#define BP_QEST BP_QUESTION + +// Space bar +#define BP_NON_BREAKING_SPACE LSFT(KC_SPACE) +#define BP_NBSP BP_NON_BREAKING_SPACE + +// AltGr-ed characters +// First row +#define BP_EN_DASH ALTGR(BP_DOLLAR) // – +#define BP_NDSH BP_EN_DASH +#define BP_EM_DASH ALTGR(KC_1) // — +#define BP_MDSH BP_EM_DASH +#define BP_LESS ALTGR(KC_2) // < +#define BP_GREATER ALTGR(KC_3) // > +#define BP_GRTR BP_GREATER +#define BP_LBRACKET ALTGR(KC_4) // [ +#define BP_LBRC BP_LBRACKET +#define BP_RBRACKET ALTGR(KC_5) // ] +#define BP_RBRC BP_RBRACKET +#define BP_CIRCUMFLEX ALTGR(KC_6) // ^ +#define BP_CIRC BP_CIRCUMFLEX +#define BP_PLUS_MINUS ALTGR(KC_7) // ± +#define BP_PSMS BP_PLUS_MINUS +#define BP_MATH_MINUS ALTGR(KC_8) // − +#define BP_MMNS BP_MATH_MINUS +#define BP_OBELUS ALTGR(KC_9) // ÷ +#define BP_OBEL BP_OBELUS +// more conventional name of the symbol +#define BP_DIVISION_SIGN BP_OBELUS +#define BP_DVSN BP_DIVISION_SIGN +#define BP_TIMES ALTGR(KC_0) // × +#define BP_TIMS BP_TIMES +#define BP_DIFFERENT ALTGR(BP_EQUAL) // ≠ +#define BP_DIFF BP_DIFFERENT +#define BP_PERMILLE ALTGR(BP_PERCENT) // ‰ +#define BP_PMIL BP_PERMILLE + +// Second row +#define BP_PIPE ALTGR(BP_B) // | +#define BP_DEAD_ACUTE ALTGR(BP_E_ACUTE) // dead ´ +#define BP_DACT BP_DEAD_ACUTE +#define BP_AMPERSAND ALTGR(BP_P) // & +#define BP_AMPR BP_AMPERSAND +#define BP_OE_LIGATURE ALTGR(BP_O) // œ +#define BP_OE BP_OE_LIGATURE +#define BP_DEAD_GRAVE ALTGR(BP_E_GRAVE) // ` +#define BP_DGRV BP_DEAD_GRAVE +#define BP_INVERTED_EXCLAIM ALTGR(BP_DEAD_CIRCUMFLEX) // ¡ +#define BP_IXLM BP_INVERTED_EXCLAIM +#define BP_DEAD_CARON ALTGR(BP_V) // dead ˇ +#define BP_DCAR BP_DEAD_CARON +#define BP_ETH ALTGR(BP_D) // ð +#define BP_DEAD_SLASH ALTGR(BP_L) // dead / +#define BP_DSLH BP_DEAD_SLASH +#define BP_IJ_LIGATURE ALTGR(BP_J) // ij +#define BP_IJ BP_IJ_LIGATURE +#define BP_SCHWA ALTGR(BP_Z) // ə +#define BP_SCWA BP_SCHWA +#define BP_DEAD_BREVE ALTGR(BP_W) // dead ˘ +#define BP_DBRV BP_DEAD_BREVE + +// Third row +#define BP_AE_LIGATURE ALTGR(BP_A) // æ +#define BP_AE BP_AE_LIGATURE +#define BP_U_GRAVE AGR(BP_U) // ù +#define BP_UGRV BP_U_GRAVE +#define BP_DEAD_TREMA ALTGR(BP_I) // dead ¨ (trema/umlaut/diaresis) +#define BP_DTRM BP_DEAD_TREMA +#define BP_EURO ALTGR(BP_E) // € +#define BP_TYPOGRAPHICAL_APOSTROPHE ALTGR(BP_COMMMA) // ’ +#define BP_TAPO BP_TYPOGRAPHICAL_APOSTROPHE +#define BP_COPYRIGHT ALTGR(BP_C) // © +#define BP_CPRT BP_COPYRIGHT +#define BP_THORN ALTGR(BP_T) // þ +#define BP_THRN BP_THORN +#define BP_SHARP_S ALTGR(BP_S) // ß +#define BP_SRPS BP_SHARP_S +#define BP_REGISTERED_TRADEMARK ALTGR(BP_R) // ® +#define BP_RTM BP_REGISTERED_TRADEMARK +#define BP_DEAD_TILDE ALTGR(BP_N) // dead ~ +#define BP_DTLD BP_DEAD_TILDE +#define BP_DEAD_MACRON ALTGR(BP_M) // dead ¯ +#define BP_DMCR BP_DEAD_MACRON +#define BP_DEAD_CEDILLA ALTGR(BP_C_CEDILLA) // dead ¸ +#define BP_DCED BP_DEAD_CEDILLA + +// Fourth row +#define BP_NONUS_SLASH ALTGR(BP_E_CIRCUMFLEX) // / on non-us backslash key (102nd key, ê in bépo) +#define BP_NUSL BP_NONUS_SLASH +#define BP_BACKSLASH ALTGR(BP_A_GRAVE) /* \ */ +#define BP_BSLS BP_BACKSLASH +#define BP_LEFT_CURLY_BRACE ALTGR(BP_Y) // { +#define BP_LCBR BP_LEFT_CURLY_BRACE +#define BP_RIGHT_CURLY_BRACE ALTGR(BP_X) // } +#define BP_RCBR BP_RIGHT_CURLY_BRACE +#define BP_ELLIPSIS ALTGR(BP_DOT) // … +#define BP_ELPS BP_ELLIPSIS +#define BP_TILDE ALTGR(BP_K) // ~ +#define BP_TILD BP_TILDE +#define BP_INVERTED_QUESTION ALTGR(BP_QUESTION) // ¿ +#define BP_IQST BP_INVERTED_QUESTION +#define BP_DEAD_RING ALTGR(BP_Q) // dead ° +#define BP_DRNG BP_DEAD_RING +#define BP_DEAD_GREEK ALTGR(BP_G) // dead Greek key (following key will make a Greek letter) +#define BP_DGRK BP_DEAD_GREEK +#define BP_DAGGER ALTGR(BP_H) // † +#define BP_DAGR BP_DAGGER +#define BP_DEAD_OGONEK ALTGR(BP_F) // dead ˛ +#define BP_DOGO BP_DEAD_OGONEK + +// Space bar +#define BP_UNDERSCORE ALTGR(KC_SPACE) // _ +#define BP_UNDS BP_UNDERSCORE + +// AltGr-Shifted characters (different from capitalised AltGr-ed characters) +// First row +#define BP_PARAGRAPH ALTGR(BP_HASH) // ¶ +#define BP_PARG BP_PARAGRAPH +#define BP_LOW_DOUBLE_QUOTE ALTGR(BP_1) // „ +#define BP_LWQT BP_LOW_DOUBLE_QUOTE +#define BP_LEFT_DOUBLE_QUOTE ALTGR(BP_2) // “ +#define BP_LDQT BP_LEFT_DOUBLE_QUOTE +#define BP_RIGHT_DOUBLE_QUOTE ALTGR(BP_3) // ” +#define BP_RDQT BP_RIGHT_DOUBLE_QUOTE +#define BP_LESS_OR_EQUAL ALTGR(BP_4) // ≤ +#define BP_LEQL BP_LESS_OR_EQUAL +#define BP_GREATER_OR_EQUAL ALTGR(BP_5) // ≥ +#define BP_GEQL BP_GREATER_OR_EQUAL +// nothing on ALTGR(BP_6) +#define BP_NEGATION ALTGR(BP_7) // ¬ +#define BP_NEGT BP_NEGATION +#define BP_ONE_QUARTER ALTGR(BP_8) // ¼ +#define BP_1QRT BP_ONE_QUARTER +#define BP_ONE_HALF ALTGR(BP_9) // ½ +#define BP_1HLF BP_ONE_HALF +#define BP_THREE_QUARTERS ALTGR(BP_0) // ¾ +#define BP_3QRT BP_THREE_QUARTERS +#define BP_MINUTES ALTGR(BP_DEGREE) // ′ +#define BP_MNUT BP_MINUTES +#define BP_SECONDS ALTGR(BP_GRAVE) // ″ +#define BP_SCND BP_SECONDS + +// Second row +#define BP_BROKEN_PIPE LSFT(BP_PIPE) // ¦ +#define BP_BPIP BP_BROKEN_PIPE +#define BP_DEAD_DOUBLE_ACUTE LSFT(BP_DEAD_ACUTE) // ˝ +#define BP_DDCT BP_DEAD_DOUBLE_ACUTE +#define BP_SECTION ALTGR(LSFT(BP_P)) // § +#define BP_SECT BP_SECTION +// LSFT(BP_DEAD_GRAVE) is actually the same character as LSFT(BP_PERCENT) +#define BP_GRAVE_BIS LSFT(BP_DEAD_GRAVE) // ` +#define BP_GRVB BP_GRAVE_BIS + +// Third row +#define BP_DEAD_DOT_ABOVE LSFT(BP_DEAD_TREMA) // dead ˙ +#define BP_DDTA BP_DEAD_DOT_ABOVE +#define BP_DEAD_CURRENCY LSFT(BP_EURO) // dead ¤ (next key will generate a currency code like ¥ or £) +#define BP_DCUR BP_DEAD_CURRENCY +#define BP_DEAD_HORN LSFT(ALTGR(BP_COMMA)) // dead ̛ +#define BP_DHRN BP_DEAD_HORN +#define BP_LONG_S LSFT(ALTGR(BP_C)) // ſ +#define BP_LNGS BP_LONG_S +#define BP_TRADEMARK LSFT(BP_REGISTERED_TRADEMARK) // ™ +#define BP_TM BP_TRADEMARK +#define BP_ORDINAL_INDICATOR_O LSFT(ALTGR(BP_M)) // º +#define BP_ORDO BP_ORDINAL_INDICATOR_O +#define BP_DEAD_COMMA LSFT(BP_DEAD_CEDILLA) // dead ˛ +#define BP_DCOM BP_DEAD_COMMA + +// Fourth row +#define BP_LEFT_QUOTE LSFT(ALTGR(BP_Y)) // ‘ +#define BP_LQOT BP_LEFT_QUOTE +#define BP_RIGHT_QUOTE LSFT(ALTGR(BP_X)) // ’ +#define BP_RQOT BP_RIGHT_QUOTE +#define BP_INTERPUNCT LSFT(ALTGR(BP_DOT)) // · +#define BP_IPCT BP_INTERPUNCT +#define BP_DEAD_HOOK_ABOVE LSFT(ALTGR(BP_QUESTION)) // dead ̉ +#define BP_DHKA BP_DEAD_HOOK_ABOVE +#define BP_DEAD_UNDERDOT LSFT(BP_DEAD_RING) // dead ̣ +#define BP_DUDT BP_DEAD_UNDERDOT +#define BP_DOUBLE_DAGGER LSFT(BP_DAGGER) // ‡ +#define BP_DDGR BP_DOUBLE_DAGGER +#define BP_ORDINAL_INDICATOR_A LSFT(ALTGR(BP_F)) // ª +#define BP_ORDA BP_ORDINAL_INDICATOR_A + +// Space bar +#define BP_NARROW_NON_BREAKING_SPACE ALTGR(BP_NON_BREAKING_SPACE) +#define BP_NNBS BP_NARROW_NON_BREAKING_SPACE + +#endif diff --git a/quantum/keymap_extras/keymap_colemak.h b/quantum/keymap_extras/keymap_colemak.h new file mode 100644 index 0000000000..b8d6157484 --- /dev/null +++ b/quantum/keymap_extras/keymap_colemak.h @@ -0,0 +1,75 @@ +#ifndef KEYMAP_COLEMAK_H +#define KEYMAP_COLEMAK_H + +#include "keymap.h" +// For software implementation of colemak +#define CM_Q KC_Q +#define CM_W KC_W +#define CM_F KC_E +#define CM_P KC_R +#define CM_G KC_T +#define CM_J KC_Y +#define CM_L KC_U +#define CM_U KC_I +#define CM_Y KC_O +#define CM_SCLN KC_P + +#define CM_A KC_A +#define CM_R KC_S +#define CM_S KC_D +#define CM_T KC_F +#define CM_D KC_G +#define CM_H KC_H +#define CM_N KC_J +#define CM_E KC_K +#define CM_I KC_L +#define CM_O KC_SCLN +#define CM_COLN LSFT(CM_SCLN) + +#define CM_Z KC_Z +#define CM_X KC_X +#define CM_C KC_C +#define CM_V KC_V +#define CM_B KC_B +#define CM_K KC_N +#define CM_M KC_M +#define CM_COMM KC_COMM +#define CM_DOT KC_DOT +#define CM_SLSH KC_SLSH + +// Make it easy to support these in macros +// TODO: change macro implementation so these aren't needed +#define KC_CM_Q CM_Q +#define KC_CM_W CM_W +#define KC_CM_F CM_F +#define KC_CM_P CM_P +#define KC_CM_G CM_G +#define KC_CM_J CM_J +#define KC_CM_L CM_L +#define KC_CM_U CM_U +#define KC_CM_Y CM_Y +#define KC_CM_SCLN CM_SCLN + +#define KC_CM_A CM_A +#define KC_CM_R CM_R +#define KC_CM_S CM_S +#define KC_CM_T CM_T +#define KC_CM_D CM_D +#define KC_CM_H CM_H +#define KC_CM_N CM_N +#define KC_CM_E CM_E +#define KC_CM_I CM_I +#define KC_CM_O CM_O + +#define KC_CM_Z CM_Z +#define KC_CM_X CM_X +#define KC_CM_C CM_C +#define KC_CM_V CM_V +#define KC_CM_B CM_B +#define KC_CM_K CM_K +#define KC_CM_M CM_M +#define KC_CM_COMM CM_COMM +#define KC_CM_DOT CM_DOT +#define KC_CM_SLSH CM_SLSH + +#endif diff --git a/quantum/keymap_extras/keymap_dvorak.h b/quantum/keymap_extras/keymap_dvorak.h new file mode 100644 index 0000000000..e855056e83 --- /dev/null +++ b/quantum/keymap_extras/keymap_dvorak.h @@ -0,0 +1,74 @@ +#ifndef KEYMAP_DVORAK_H +#define KEYMAP_DVORAK_H + +#include "keymap.h" + +// Normal characters +#define DV_GRV KC_GRV +#define DV_1 KC_1 +#define DV_2 KC_2 +#define DV_3 KC_3 +#define DV_4 KC_4 +#define DV_5 KC_5 +#define DV_6 KC_6 +#define DV_7 KC_7 +#define DV_8 KC_8 +#define DV_9 KC_9 +#define DV_0 KC_0 +#define DV_LBRC KC_MINS +#define DV_RBRC KC_EQL + +#define DV_QUOT KC_Q +#define DV_COMM KC_W +#define DV_DOT KC_E +#define DV_P KC_R +#define DV_Y KC_T +#define DV_F KC_Y +#define DV_G KC_U +#define DV_C KC_I +#define DV_R KC_O +#define DV_L KC_P +#define DV_SLSH KC_LBRC +#define DV_EQL KC_RBRC + +#define DV_A KC_A +#define DV_O KC_S +#define DV_E KC_D +#define DV_U KC_F +#define DV_I KC_G +#define DV_D KC_H +#define DV_H KC_J +#define DV_T KC_K +#define DV_N KC_L +#define DV_S KC_SCLN +#define DV_MINS KC_QUOT + +#define DV_SCLN KC_Z +#define DV_Q KC_X +#define DV_J KC_C +#define DV_K KC_V +#define DV_X KC_B +#define DV_B KC_N +#define DV_M KC_M +#define DV_W KC_COMM +#define DV_V KC_DOT +#define DV_Z KC_SLSH + +// Shifted characters +#define DV_TILD LSFT(DV_GRV) +#define DV_EXLM LSFT(DV_1) +#define DV_AT LSFT(DV_2) +#define DV_HASH LSFT(DV_3) +#define DV_DLR LSFT(DV_4) +#define DV_PERC LSFT(DV_5) +#define DV_CIRC LSFT(DV_6) +#define DV_AMPR LSFT(DV_7) +#define DV_ASTR LSFT(DV_8) +#define DV_LPRN LSFT(DV_9) +#define DV_RPRN LSFT(DV_0) +#define DV_LCBR LSFT(DV_LBRC) +#define DV_RCBR LSFT(DV_RBRC) +#define DV_UNDS LSFT(DV_MINS) +#define DV_PLUS LSFT(DV_EQL) + +#endif diff --git a/quantum/keymap_extras/keymap_fr_ch.h b/quantum/keymap_extras/keymap_fr_ch.h new file mode 100644 index 0000000000..3fd9713575 --- /dev/null +++ b/quantum/keymap_extras/keymap_fr_ch.h @@ -0,0 +1,98 @@ +#ifndef KEYMAP_FR_CH +#define KEYMAP_FR_CH + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define FR_CH_ALGR KC_RALT + +// normal characters +#define FR_CH_Z KC_Y +#define FR_CH_Y KC_Z + +#define FR_CH_A KC_A +#define FR_CH_B KC_B +#define FR_CH_C KC_C +#define FR_CH_D KC_D +#define FR_CH_E KC_E +#define FR_CH_F KC_F +#define FR_CH_G KC_G +#define FR_CH_H KC_H +#define FR_CH_I KC_I +#define FR_CH_J KC_J +#define FR_CH_K KC_K +#define FR_CH_L KC_L +#define FR_CH_M KC_M +#define FR_CH_N KC_N +#define FR_CH_O KC_O +#define FR_CH_P KC_P +#define FR_CH_Q KC_Q +#define FR_CH_R KC_R +#define FR_CH_S KC_S +#define FR_CH_T KC_T +#define FR_CH_U KC_U +#define FR_CH_V KC_V +#define FR_CH_W KC_W +#define FR_CH_X KC_X + +#define FR_CH_0 KC_0 +#define FR_CH_1 KC_1 +#define FR_CH_2 KC_2 +#define FR_CH_3 KC_3 +#define FR_CH_4 KC_4 +#define FR_CH_5 KC_5 +#define FR_CH_6 KC_6 +#define FR_CH_7 KC_7 +#define FR_CH_8 KC_8 +#define FR_CH_9 KC_9 + +#define FR_CH_DOT KC_DOT +#define FR_CH_COMM KC_COMM + +#define FR_CH_QUOT KC_MINS +#define FR_CH_AE KC_QUOT +#define FR_CH_UE KC_LBRC +#define FR_CH_OE KC_SCLN + +#define FR_CH_CIRC KC_EQL // accent circumflex ^ and grave ` and ~ +#define FR_CH_LESS KC_NUBS // < and > and backslash +#define FR_CH_MINS KC_SLSH // - and _ +#define FR_CH_DLR KC_BSLS // $, £ and } +#define FR_CH_PARA KC_GRV // § and ring ° +#define FR_CH_DIAE KC_RBRC // accent ¨ + +// shifted characters +#define FR_CH_RING LSFT(KC_GRV) // ° +#define FR_CH_EXLM LSFT(KC_RBRC) // ! +#define FR_CH_PLUS LSFT(KC_1) // + +#define FR_CH_DQOT LSFT(KC_2) // " +#define FR_CH_ASTR LSFT(KC_3) // * +#define FR_CH_PERC LSFT(KC_5) // % +#define FR_CH_AMPR LSFT(KC_6) // & +#define FR_CH_SLSH LSFT(KC_7) // / +#define FR_CH_LPRN LSFT(KC_8) // ( +#define FR_CH_RPRN LSFT(KC_9) // ) +#define FR_CH_EQL LSFT(KC_0) // = +#define FR_CH_QST LSFT(FR_CH_QUOT) // ? +#define FR_CH_MORE LSFT(FR_CH_LESS) // > +#define FR_CH_COLN LSFT(KC_DOT) // : +#define FR_CH_SCLN LSFT(KC_COMM) // ; +#define FR_CH_UNDS LSFT(FR_CH_MINS) // _ +#define FR_CH_CCED LSFT(KC_4) // ç +#define FR_CH_GRV LSFT(FR_CH_CIRC) // accent grave ` + +// Alt Gr-ed characters +#define FR_CH_LCBR ALGR(KC_QUOT) // { +#define FR_CH_LBRC ALGR(KC_LBRC) // [ +#define FR_CH_RBRC ALGR(KC_9) // ] +#define FR_CH_RCBR ALGR(KC_0) // } +#define FR_CH_BSLS ALGR(FR_CH_LESS) // backslash +#define FR_CH_AT ALGR(KC_2) // @ +#define FR_CH_EURO ALGR(KC_E) // € +#define FR_CH_TILD ALGR(FR_CH_CIRC) // ~ +#define FR_CH_PIPE ALGR(KC_1) // | +#define FR_CH_HASH ALGR(KC_3) // # +#define FR_CH_ACUT ALGR(FR_CH_QUOT) // accent acute ´ + +#endif diff --git a/quantum/keymap_extras/keymap_french.h b/quantum/keymap_extras/keymap_french.h new file mode 100644 index 0000000000..2a44c80b14 --- /dev/null +++ b/quantum/keymap_extras/keymap_french.h @@ -0,0 +1,83 @@ +#ifndef KEYMAP_FRENCH_H +#define KEYMAP_FRENCH_H + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define NO_ALGR KC_RALT + +// Normal characters +#define FR_SUP2 KC_GRV +#define FR_AMP KC_1 +#define FR_EACU KC_2 +#define FR_QUOT KC_3 +#define FR_APOS KC_4 +#define FR_LPRN KC_5 +#define FR_MINS KC_6 +#define FR_EGRV KC_7 +#define FR_UNDS KC_8 +#define FR_CCED KC_9 +#define FR_AGRV KC_0 +#define FR_RPRN KC_MINS +#define FR_EQL KC_EQL + +#define FR_A KC_Q +#define FR_Z KC_W +#define FR_CIRC KC_LBRC +#define FR_DLR KC_RBRC + +#define FR_Q KC_A +#define FR_M KC_SCLN +#define FR_UGRV KC_QUOT +#define FR_ASTR KC_NUHS + +#define FR_LESS KC_NUBS +#define FR_W KC_Z +#define FR_COMM KC_M +#define FR_SCLN KC_COMM +#define FR_COLN KC_DOT +#define FR_EXLM KC_SLSH + +// Shifted characters +#define FR_1 LSFT(KC_1) +#define FR_2 LSFT(KC_2) +#define FR_3 LSFT(KC_3) +#define FR_4 LSFT(KC_4) +#define FR_5 LSFT(KC_5) +#define FR_6 LSFT(KC_6) +#define FR_7 LSFT(KC_7) +#define FR_8 LSFT(KC_8) +#define FR_9 LSFT(KC_9) +#define FR_0 LSFT(KC_0) +#define FR_OVRR LSFT(FR_RPRN) +#define FR_PLUS LSFT(FR_EQL) + +#define FR_UMLT LSFT(FR_CIRC) +#define FR_PND LSFT(FR_DLR) +#define FR_PERC LSFT(FR_UGRV) +#define FR_MU LSFT(FR_ASTR) + +#define FR_GRTR LSFT(FR_LESS) +#define FR_QUES LSFT(FR_COMM) +#define FR_DOT LSFT(FR_SCLN) +#define FR_SLSH LSFT(FR_COLN) +#define FR_SECT LSFT(FR_EXLM) + +// Alt Gr-ed characters +#define FR_TILD ALGR(KC_2) +#define FR_HASH ALGR(KC_3) +#define FR_LCBR ALGR(KC_4) +#define FR_LBRC ALGR(KC_5) +#define FR_PIPE ALGR(KC_6) +#define FR_GRV ALGR(KC_7) +#define FR_BSLS ALGR(KC_8) +#define FR_CIRC ALGR(KC_9) +#define FR_AT ALGR(KC_0) +#define FR_RBRC ALGR(FR_RPRN) +#define FR_RCBR ALGR(FR_EQL) + +#define FR_EURO ALGR(KC_E) +#define FR_BULT ALGR(FR_DLR) + +#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 0000000000..004d73ee23 --- /dev/null +++ b/quantum/keymap_extras/keymap_french_osx.h @@ -0,0 +1,77 @@ +#ifndef KEYMAP_FRENCH_OSX_H +#define KEYMAP_FRENCH_OSX_H + +#include "keymap.h" + +// Normal characters +#define FR_AT KC_GRV +#define FR_AMP KC_1 +#define FR_EACU KC_2 +#define FR_QUOT KC_3 +#define FR_APOS KC_4 +#define FR_LPRN KC_5 +#define FR_SECT KC_6 +#define FR_EGRV KC_7 +#define FR_EXLM KC_8 +#define FR_CCED KC_9 +#define FR_AGRV KC_0 +#define FR_RPRN KC_MINS +#define FR_MINS KC_EQL + +#define FR_A KC_Q +#define FR_Z KC_W +#define FR_CIRC KC_LBRC +#define FR_DLR KC_RBRC + +#define FR_Q KC_A +#define FR_M KC_SCLN +#define FR_UGRV KC_QUOT +#define FR_GRV KC_NUHS + +#define FR_LESS KC_NUBS +#define FR_W KC_Z +#define FR_COMM KC_M +#define FR_SCLN KC_COMM +#define FR_COLN KC_DOT +#define FR_EQL KC_SLSH + +// Shifted characters +#define FR_HASH LSFT(KC_GRV) +#define FR_1 LSFT(KC_1) +#define FR_2 LSFT(KC_2) +#define FR_3 LSFT(KC_3) +#define FR_4 LSFT(KC_4) +#define FR_5 LSFT(KC_5) +#define FR_6 LSFT(KC_6) +#define FR_7 LSFT(KC_7) +#define FR_8 LSFT(KC_8) +#define FR_9 LSFT(KC_9) +#define FR_0 LSFT(KC_0) +#define FR_UNDS LSFT(FR_MINS) + +#define FR_UMLT LSFT(FR_CIRC) +#define FR_ASTR LSFT(FR_DLR) + +#define FR_PERC LSFT(FR_UGRV) +#define FR_PND LSFT(FR_GRV) + +#define FR_GRTR LSFT(FR_LESS) +#define FR_QUES LSFT(FR_COMM) +#define FR_DOT LSFT(FR_SCLN) +#define FR_SLSH LSFT(FR_COLN) +#define FR_PLUS LSFT(FR_EQL) + +// Alted characters +#define FR_LCBR LALT(KC_5) +#define FR_RCBR LALT(FR_RPRN) +#define FR_EURO LALT(KC_E) +#define FR_BULT LALT(FR_DLR) +#define FR_TILD LALT(KC_N) + +// Shift+Alt-ed characters +#define FR_LBRC LSFT(LALT(KC_5)) +#define FR_RBRC LSFT(LALT(FR_RPRN)) +#define FR_PIPE LSFT(LALT(KC_L)) +#define FR_BSLS LSFT(LALT(FR_COLN)) + +#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 0000000000..3f9ae8bade --- /dev/null +++ b/quantum/keymap_extras/keymap_german.h @@ -0,0 +1,99 @@ +#ifndef KEYMAP_GERMAN +#define KEYMAP_GERMAN + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define DE_ALGR KC_RALT + +// normal characters +#define DE_Z KC_Y +#define DE_Y KC_Z + +#define DE_A KC_A +#define DE_B KC_B +#define DE_C KC_C +#define DE_D KC_D +#define DE_E KC_E +#define DE_F KC_F +#define DE_G KC_G +#define DE_H KC_H +#define DE_I KC_I +#define DE_J KC_J +#define DE_K KC_K +#define DE_L KC_L +#define DE_M KC_M +#define DE_N KC_N +#define DE_O KC_O +#define DE_P KC_P +#define DE_Q KC_Q +#define DE_R KC_R +#define DE_S KC_S +#define DE_T KC_T +#define DE_U KC_U +#define DE_V KC_V +#define DE_W KC_W +#define DE_X KC_X + +#define DE_0 KC_0 +#define DE_1 KC_1 +#define DE_2 KC_2 +#define DE_3 KC_3 +#define DE_4 KC_4 +#define DE_5 KC_5 +#define DE_6 KC_6 +#define DE_7 KC_7 +#define DE_8 KC_8 +#define DE_9 KC_9 + +#define DE_DOT KC_DOT +#define DE_COMM KC_COMM + +#define DE_SS KC_MINS +#define DE_AE KC_QUOT +#define DE_UE KC_LBRC +#define DE_OE KC_SCLN + +#define DE_CIRC KC_GRAVE // accent circumflex ^ and ring ° +#define DE_ACUT KC_EQL // accent acute ´ and grave ` +#define DE_PLUS KC_RBRC // + and * and ~ +#define DE_HASH KC_BSLS // # and ' +#define DE_LESS KC_NUBS // < and > and | +#define DE_MINS KC_SLSH // - and _ + +// shifted characters +#define DE_RING LSFT(DE_CIRC) // ° +#define DE_EXLM LSFT(KC_1) // ! +#define DE_DQOT LSFT(KC_2) // " +#define DE_PARA LSFT(KC_3) // § +#define DE_DLR LSFT(KC_4) // $ +#define DE_PERC LSFT(KC_5) // % +#define DE_AMPR LSFT(KC_6) // & +#define DE_SLSH LSFT(KC_7) // / +#define DE_LPRN LSFT(KC_8) // ( +#define DE_RPRN LSFT(KC_9) // ) +#define DE_EQL LSFT(KC_0) // = +#define DE_QST LSFT(DE_SS) // ? +#define DE_GRV LSFT(DE_ACUT) // ` +#define DE_ASTR LSFT(DE_PLUS) // * +#define DE_QUOT LSFT(DE_HASH) // ' +#define DE_MORE LSFT(DE_LESS) // > +#define DE_COLN LSFT(KC_DOT) // : +#define DE_SCLN LSFT(KC_COMM) // ; +#define DE_UNDS LSFT(DE_MINS) // _ + +// Alt Gr-ed characters +#define DE_SQ2 ALGR(KC_2) // ² +#define DE_SQ3 ALGR(KC_3) // ³ +#define DE_LCBR ALGR(KC_7) // { +#define DE_LBRC ALGR(KC_8) // [ +#define DE_RBRC ALGR(KC_9) // ] +#define DE_RCBR ALGR(KC_0) // } +#define DE_BSLS ALGR(DE_SS) // backslash +#define DE_AT ALGR(KC_Q) // @ +#define DE_EURO ALGR(KC_E) // € +#define DE_TILD ALGR(DE_PLUS) // ~ +#define DE_PIPE ALGR(DE_LESS) // | + +#endif diff --git a/quantum/keymap_extras/keymap_german_ch.h b/quantum/keymap_extras/keymap_german_ch.h new file mode 100644 index 0000000000..6a782bcd7b --- /dev/null +++ b/quantum/keymap_extras/keymap_german_ch.h @@ -0,0 +1,102 @@ +#ifndef KEYMAP_SWISS_GERMAN +#define KEYMAP_SWISS_GERMAN + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define CH_ALGR KC_RALT + +// normal characters +#define CH_Z KC_Y +#define CH_Y KC_Z + +#define CH_A KC_A +#define CH_B KC_B +#define CH_C KC_C +#define CH_D KC_D +#define CH_E KC_E +#define CH_F KC_F +#define CH_G KC_G +#define CH_H KC_H +#define CH_I KC_I +#define CH_J KC_J +#define CH_K KC_K +#define CH_L KC_L +#define CH_M KC_M +#define CH_N KC_N +#define CH_O KC_O +#define CH_P KC_P +#define CH_Q KC_Q +#define CH_R KC_R +#define CH_S KC_S +#define CH_T KC_T +#define CH_U KC_U +#define CH_V KC_V +#define CH_W KC_W +#define CH_X KC_X + +#define CH_0 KC_0 +#define CH_1 KC_1 +#define CH_2 KC_2 +#define CH_3 KC_3 +#define CH_4 KC_4 +#define CH_5 KC_5 +#define CH_6 KC_6 +#define CH_7 KC_7 +#define CH_8 KC_8 +#define CH_9 KC_9 + +#define CH_DOT KC_DOT +#define CH_COMM KC_COMM + +#define CH_QUOT KC_MINS // ' ? ´ +#define CH_AE KC_QUOT +#define CH_UE KC_LBRC +#define CH_OE KC_SCLN + +#define CH_PARA KC_GRAVE // secction sign § and ° +#define CH_CARR KC_EQL // carret ^ ` ~ +#define CH_DIER KC_RBRC // dieresis ¨ ! ] +#define CH_DLR KC_BSLS // $ £ } +#define CH_LESS KC_NUBS // < and > and backslash +#define CH_MINS KC_SLSH // - and _ + +// shifted characters +#define CH_RING LSFT(CH_PARA) // ° +#define CH_PLUS LSFT(KC_1) // + +#define CH_DQOT LSFT(KC_2) // " +#define CH_PAST LSFT(KC_3) // * +#define CH_CELA LSFT(KC_4) // ç +#define CH_PERC LSFT(KC_5) // % +#define CH_AMPR LSFT(KC_6) // & +#define CH_SLSH LSFT(KC_7) // / +#define CH_LPRN LSFT(KC_8) // ( +#define CH_RPRN LSFT(KC_9) // ) +#define CH_EQL LSFT(KC_0) // = +#define CH_QST LSFT(CH_QUOT) // ? +#define CH_GRV LSFT(CH_CARR) // ` +#define CH_EXLM LSFT(CH_DIER) // ! +#define CH_POND LSFT(CH_DLR) // £ +#define CH_MORE LSFT(CH_LESS) // > +#define CH_COLN LSFT(KC_DOT) // : +#define CH_SCLN LSFT(KC_COMM) // ; +#define CH_UNDS LSFT(CH_MINS) // _ + +// Alt Gr-ed characters +#define CH_BRBR ALGR(KC_1) // ¦ brocken bar +#define CH_AT ALGR(KC_2) // @ +#define CH_HASH ALGR(KC_3) // # +#define CH_NOTL ALGR(KC_6) // ¬ negative logic +#define CH_PIPE ALGR(KC_7) // | +#define CH_CENT ALGR(KC_8) // ¢ cent +#define CH_ACUT ALGR(CH_QUOT) // ´ +#define CH_TILD ALGR(CH_CARR) // ~ +#define CH_EURO ALGR(KC_E) // € +#define CH_LBRC ALGR(CH_UE) // [ +#define CH_RBRC ALGR(CH_DIER) // ] +#define CH_LCBR ALGR(CH_AE) // { +#define CH_RCBR ALGR(CH_DLR) // } +#define CH_BSLS ALGR(CH_LESS) // backslash + +#endif diff --git a/quantum/keymap_extras/keymap_german_osx.h b/quantum/keymap_extras/keymap_german_osx.h new file mode 100644 index 0000000000..f63f066183 --- /dev/null +++ b/quantum/keymap_extras/keymap_german_osx.h @@ -0,0 +1,97 @@ +#ifndef KEYMAP_GERMAN_OSX +#define KEYMAP_GERMAN_OSX + +#include "keymap.h" + +// Alt gr + +// normal characters +#define DE_OSX_Z KC_Y +#define DE_OSX_Y KC_Z + +#define DE_OSX_A KC_A +#define DE_OSX_B KC_B +#define DE_OSX_C KC_C +#define DE_OSX_D KC_D +#define DE_OSX_E KC_E +#define DE_OSX_F KC_F +#define DE_OSX_G KC_G +#define DE_OSX_H KC_H +#define DE_OSX_I KC_I +#define DE_OSX_J KC_J +#define DE_OSX_K KC_K +#define DE_OSX_L KC_L +#define DE_OSX_M KC_M +#define DE_OSX_N KC_N +#define DE_OSX_O KC_O +#define DE_OSX_P KC_P +#define DE_OSX_Q KC_Q +#define DE_OSX_R KC_R +#define DE_OSX_S KC_S +#define DE_OSX_T KC_T +#define DE_OSX_U KC_U +#define DE_OSX_V KC_V +#define DE_OSX_W KC_W +#define DE_OSX_X KC_X + +#define DE_OSX_0 KC_0 +#define DE_OSX_1 KC_1 +#define DE_OSX_2 KC_2 +#define DE_OSX_3 KC_3 +#define DE_OSX_4 KC_4 +#define DE_OSX_5 KC_5 +#define DE_OSX_6 KC_6 +#define DE_OSX_7 KC_7 +#define DE_OSX_8 KC_8 +#define DE_OSX_9 KC_9 + +#define DE_OSX_DOT KC_DOT +#define DE_OSX_COMM KC_COMM + +#define DE_OSX_SS KC_MINS +#define DE_OSX_AE KC_QUOT +#define DE_OSX_UE KC_LBRC +#define DE_OSX_OE KC_SCLN + +#define DE_OSX_CIRC KC_NUBS // accent circumflex ^ and ring ° +#define DE_OSX_ACUT KC_EQL // accent acute ´ and grave ` +#define DE_OSX_PLUS KC_RBRC // + and * and ~ +#define DE_OSX_HASH KC_BSLS // # and ' +#define DE_OSX_LESS KC_GRV // < and > and | +#define DE_OSX_MINS KC_SLSH // - and _ + +// shifted characters +#define DE_OSX_RING LSFT(DE_OSX_CIRC) // ° +#define DE_OSX_EXLM LSFT(KC_1) // ! +#define DE_OSX_DQOT LSFT(KC_2) // " +#define DE_OSX_PARA LSFT(KC_3) // § +#define DE_OSX_DLR LSFT(KC_4) // $ +#define DE_OSX_PERC LSFT(KC_5) // % +#define DE_OSX_AMPR LSFT(KC_6) // & +#define DE_OSX_SLSH LSFT(KC_7) // / +#define DE_OSX_LPRN LSFT(KC_8) // ( +#define DE_OSX_RPRN LSFT(KC_9) // ) +#define DE_OSX_EQL LSFT(KC_0) // = +#define DE_OSX_QST LSFT(DE_OSX_SS) // ? +#define DE_OSX_GRV LSFT(DE_OSX_ACUT) // ` +#define DE_OSX_ASTR LSFT(DE_OSX_PLUS) // * +#define DE_OSX_QUOT LSFT(DE_OSX_HASH) // ' +#define DE_OSX_MORE LSFT(DE_OSX_LESS) // > +#define DE_OSX_COLN LSFT(KC_DOT) // : +#define DE_OSX_SCLN LSFT(KC_COMM) // ; +#define DE_OSX_UNDS LSFT(DE_OSX_MINS) // _ + +// Alt-ed characters +//#define DE_OSX_SQ2 LALT(KC_2) // ² +//#define DE_OSX_SQ3 LALT(KC_3) // ³ +#define DE_OSX_LCBR LALT(KC_8) // { +#define DE_OSX_LBRC LALT(KC_5) // [ +#define DE_OSX_RBRC LALT(KC_6) // ] +#define DE_OSX_RCBR LALT(KC_9) // } +#define DE_OSX_BSLS LALT(LSFT(KC_7)) // backslash +#define DE_OSX_AT LALT(DE_OSX_L) // @ +#define DE_OSX_EURO LALT(KC_E) // € +#define DE_OSX_TILD LALT(DE_OSX_N) // ~ +#define DE_OSX_PIPE LALT(DE_OSX_7) // | + +#endif diff --git a/quantum/keymap_extras/keymap_neo2.h b/quantum/keymap_extras/keymap_neo2.h new file mode 100644 index 0000000000..80439af347 --- /dev/null +++ b/quantum/keymap_extras/keymap_neo2.h @@ -0,0 +1,63 @@ +#ifndef KEYMAP_NEO2 +#define KEYMAP_NEO2 + +#include "keymap.h" +#include "keymap_german.h" + +#define NEO_A KC_D +#define NEO_B KC_N +#define NEO_C KC_R +#define NEO_D DE_OE +#define NEO_E KC_F +#define NEO_F KC_O +#define NEO_G KC_I +#define NEO_H KC_U +#define NEO_I KC_S +#define NEO_J DE_MINS +#define NEO_K DE_Z +#define NEO_L KC_E +#define NEO_M KC_M +#define NEO_N KC_J +#define NEO_O KC_G +#define NEO_P KC_V +#define NEO_Q KC_P +#define NEO_R KC_K +#define NEO_S KC_H +#define NEO_T KC_L +#define NEO_U KC_A +#define NEO_V KC_W +#define NEO_W KC_T +#define NEO_X KC_Q +#define NEO_Y DE_AE +#define NEO_Z KC_B +#define NEO_AE KC_C +#define NEO_OE KC_X +#define NEO_UE DE_Y +#define NEO_SS DE_UE + +#define NEO_DOT DE_DOT +#define NEO_COMM DE_COMM + +#define NEO_1 DE_1 +#define NEO_2 DE_2 +#define NEO_3 DE_3 +#define NEO_4 DE_4 +#define NEO_5 DE_5 +#define NEO_6 DE_6 +#define NEO_7 DE_7 +#define NEO_8 DE_8 +#define NEO_9 DE_9 +#define NEO_0 DE_0 +#define NEO_MINS DE_SS + +#define NEO_ACUT DE_PLUS +#define NEO_GRV DE_ACUT +#define NEO_CIRC DE_CIRC + +#define NEO_L1_L KC_CAPS +#define NEO_L1_R DE_HASH + +#define NEO_L2_L DE_LESS +#define NEO_L2_R DE_ALGR + +#endif diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h new file mode 100644 index 0000000000..3acb8b6983 --- /dev/null +++ b/quantum/keymap_extras/keymap_nordic.h @@ -0,0 +1,59 @@ +#ifndef KEYMAP_NORDIC_H +#define KEYMAP_NORDIC_H + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define NO_ALGR KC_RALT + +// Normal characters +#define NO_HALF KC_GRV +#define NO_PLUS KC_MINS +#define NO_ACUT KC_EQL + +#define NO_AM KC_LBRC +#define NO_QUOT KC_RBRC +#define NO_AE KC_SCLN +#define NO_OSLH KC_QUOT +#define NO_APOS KC_NUHS + +#define NO_LESS KC_NUBS +#define NO_MINS KC_SLSH + +// Shifted characters +#define NO_SECT LSFT(NO_HALF) +#define NO_QUO2 LSFT(KC_2) +#define NO_BULT LSFT(KC_4) +#define NO_AMP LSFT(KC_6) +#define NO_SLSH LSFT(KC_7) +#define NO_LPRN LSFT(KC_8) +#define NO_RPRN LSFT(KC_9) +#define NO_EQL LSFT(KC_0) +#define NO_QUES LSFT(NO_PLUS) +#define NO_GRV LSFT(NO_ACUT) + +#define NO_CIRC LSFT(NO_QUOT) + +#define NO_GRTR LSFT(NO_LESS) +#define NO_SCLN LSFT(KC_COMM) +#define NO_COLN LSFT(KC_DOT) +#define NO_UNDS LSFT(NO_MINS) + +// Alt Gr-ed characters +#define NO_AT ALGR(KC_2) +#define NO_PND ALGR(KC_3) +#define NO_DLR ALGR(KC_4) +#define NO_LCBR ALGR(KC_7) +#define NO_LBRC ALGR(KC_8) +#define NO_RBRC ALGR(KC_9) +#define NO_RCBR ALGR(KC_0) +#define NO_PIPE ALGR(KC_NUBS) + +#define NO_EURO ALGR(KC_E) +#define NO_TILD ALGR(NO_QUOT) + +#define NO_BSLS ALGR(KC_MINS) +#define NO_MU ALGR(KC_M) + +#endif diff --git a/quantum/keymap_extras/keymap_norwegian.h b/quantum/keymap_extras/keymap_norwegian.h new file mode 100644 index 0000000000..018bfeae59 --- /dev/null +++ b/quantum/keymap_extras/keymap_norwegian.h @@ -0,0 +1,41 @@ +#ifndef KEYMAP_NORWEGIAN_H +#define KEYMAP_NORWEGIAN_H + +#include "keymap_nordic.h" + +// There are slight differrences in the keyboards in the nordic contries + +// Norwegian redifinitions from the nordic keyset +#undef NO_ACUT +#define NO_ACUT ALGR(NO_BSLS) // ´ +#undef NO_AE +#define NO_AE KC_QUOT // æ +#undef NO_BSLS +#define NO_BSLS KC_EQL // '\' +#undef NO_CIRC +#define NO_CIRC LSFT(C_RBRC) // ^ +#undef NO_GRV +#define NO_GRV LSFT(NO_BSLS) // +#undef NO_OSLH +#define NO_OSLH KC_SCLN // ø +#undef NO_PIPE +#define NO_PIPE KC_GRV // | + +// Additional norwegian keys not defined in the nordic keyset +#define NO_AA KC_LBRC // å +#define NO_ASTR LSFT(KC_BSLS) // * + +// Norwegian unique MAC characters +#define NO_ACUT_MAC KC_EQL // = +#define NO_APOS_MAC KC_NUBS // ' +#define NO_AT_MAC KC_BSLS // @ +#define NO_BSLS_MAC ALGR(LSFT(KC_7)) // '\' +#define NO_DLR_MAC LSFT(KC_4) // $ +#define NO_GRV_MAC ALGR(NO_BSLS) // ` +#define NO_GRTR_MAC LSFT(KC_GRV) // > +#define NO_LCBR_MAC ALGR(LSFT(KC_8)) // } +#define NO_LESS_MAC KC_GRV // > +#define NO_PIPE_MAC ALGR(KC_7) // | +#define NO_RCBR_MAC ALGR(LSFT(KC_9)) // } + +#endif diff --git a/quantum/keymap_extras/keymap_plover.h b/quantum/keymap_extras/keymap_plover.h new file mode 100644 index 0000000000..9b88f7d84d --- /dev/null +++ b/quantum/keymap_extras/keymap_plover.h @@ -0,0 +1,32 @@ +#ifndef KEYMAP_PLOVER_H +#define KEYMAP_PLOVER_H + +#include "keymap.h" + +#define PV_NUM KC_1 +#define PV_LS KC_Q +#define PV_LT KC_W +#define PV_LP KC_E +#define PV_LH KC_R +#define PV_LK KC_S +#define PV_LW KC_D +#define PV_LR KC_F + +#define PV_STAR KC_Y +#define PV_RF KC_U +#define PV_RP KC_I +#define PV_RL KC_O +#define PV_RT KC_P +#define PV_RD KC_LBRC +#define PV_RR KC_J +#define PV_RB KC_K +#define PV_RG KC_L +#define PV_RS KC_SCLN +#define PV_RZ KC_QUOT + +#define PV_A KC_C +#define PV_O KC_V +#define PV_E KC_N +#define PV_U KC_M + +#endif diff --git a/quantum/keymap_extras/keymap_spanish.h b/quantum/keymap_extras/keymap_spanish.h new file mode 100644 index 0000000000..af76e39fcb --- /dev/null +++ b/quantum/keymap_extras/keymap_spanish.h @@ -0,0 +1,62 @@ +#ifndef KEYMAP_SPANISH_H +#define KEYMAP_SPANISH_H + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define NO_ALGR KC_RALT + +// Normal characters +#define ES_OVRR KC_GRV +#define ES_APOS KC_MINS +#define ES_IEXL KC_EQL + +#define ES_GRV KC_LBRC +#define ES_PLUS KC_RBRC + +#define ES_NTIL KC_SCLN +#define ES_ACUT KC_QUOT +#define ES_CCED KC_NUHS + +#define ES_LESS KC_NUBS +#define ES_MINS KC_SLSH + +// Shifted characters +#define ES_ASML LSFT(ES_OVRR) +#define ES_QUOT LSFT(KC_2) +#define ES_OVDT LSFT(KC_3) +#define ES_AMPR LSFT(KC_6) +#define ES_SLSH LSFT(KC_7) +#define ES_LPRN LSFT(KC_8) +#define ES_RPRN LSFT(KC_9) +#define ES_EQL LSFT(KC_0) +#define ES_QUES LSFT(ES_APOS) +#define ES_IQUE LSFT(ES_IEXL) + +#define ES_CIRC LSFT(ES_GRV) +#define ES_ASTR LSFT(ES_PLUS) + +#define ES_UMLT LSFT(ES_GRV) + +#define ES_GRTR LSFT(ES_LESS) +#define ES_SCLN LSFT(ES_COMM) +#define ES_COLN LSFT(ES_DOT) +#define ES_UNDS LSFT(ES_MINS) + +// Alt Gr-ed characters +#define ES_BSLS ALGR(ES_OVRR) +#define ES_PIPE ALGR(KC_1) +#define ES_AT ALGR(KC_2) +#define ES_HASH ALGR(KC_3) +#define ES_TILD ALGR(ES_NTIL) +#define ES_EURO ALGR(KC_5) +#define ES_NOT ALGR(KC_6) + +#define ES_LBRC ALGR(ES_GRV) +#define ES_RBRC ALGR(ES_PLUS) + +#define ES_LCBR ALGR(ES_ACUT) +#define ES_RCRB ALGR(ES_CCED) + +#endif diff --git a/quantum/keymap_extras/keymap_uk.h b/quantum/keymap_extras/keymap_uk.h new file mode 100644 index 0000000000..5c5d951791 --- /dev/null +++ b/quantum/keymap_extras/keymap_uk.h @@ -0,0 +1,36 @@ +#ifndef KEYMAP_UK_H +#define KEYMAP_UK_H + +#include "keymap.h" + +// Alt gr +#define ALGR(kc) kc | 0x1400 +#define NO_ALGR KC_RALT + +// Normal characters +#define UK_HASH KC_NUHS + +#define UK_BSLS KC_NUBS + +// Shifted characters +#define UK_NOT LSFT(KC_GRV) +#define UK_QUOT LSFT(KC_2) +#define UK_PND LSFT(KC_3) + +#define UK_AT LSFT(KC_QUOT) +#define UK_TILD LSFT(KC_NUHS) + +#define UK_PIPE LSFT(KC_NUBS) + +// Alt Gr-ed characters +#define UK_BRKP ALGR(KC_GRV) +#define UK_EURO ALGR(KC_4) + +#define UK_EACT ALGR(KC_E) +#define UK_UACT ALGR(KC_U) +#define UK_IACT ALGR(KC_I) +#define UK_OACT ALGR(KC_O) + +#define UK_AACT ALGR(KC_A) + +#endif
\ No newline at end of file diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c new file mode 100755 index 0000000000..f20043067e --- /dev/null +++ b/quantum/light_ws2812.c @@ -0,0 +1,181 @@ +/* +* light weight WS2812 lib V2.0b +* +* Controls WS2811/WS2812/WS2812B RGB-LEDs +* Author: Tim (cpldcpu@gmail.com) +* +* Jan 18th, 2014 v2.0b Initial Version +* Nov 29th, 2015 v2.3 Added SK6812RGBW support +* +* License: GNU GPL v2 (see License.txt) +*/ + +#include "light_ws2812.h" +#include <avr/interrupt.h> +#include <avr/io.h> +#include <util/delay.h> +#include "debug.h" + +// Setleds for standard RGB +void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) +{ + ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); +} + +void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) +{ + ws2812_DDRREG |= pinmask; // Enable DDR + ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); + _delay_us(50); +} + +// Setleds for SK6812RGBW +void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) +{ + ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR + ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin)); + _delay_us(80); +} + +void ws2812_sendarray(uint8_t *data,uint16_t datlen) +{ + ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin)); +} + +/* + This routine writes an array of bytes with RGB values to the Dataout pin + using the fast 800kHz clockless WS2811/2812 protocol. +*/ + +// Timing in ns +#define w_zeropulse 350 +#define w_onepulse 900 +#define w_totalperiod 1250 + +// Fixed cycles used by the inner loop +#define w_fixedlow 2 +#define w_fixedhigh 4 +#define w_fixedtotal 8 + +// Insert NOPs to match the timing, if possible +#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000) +#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000) +#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000) + +// w1 - nops between rising edge and falling edge - low +#define w1 (w_zerocycles-w_fixedlow) +// w2 nops between fe low and fe high +#define w2 (w_onecycles-w_fixedhigh-w1) +// w3 nops to complete loop +#define w3 (w_totalcycles-w_fixedtotal-w1-w2) + +#if w1>0 + #define w1_nops w1 +#else + #define w1_nops 0 +#endif + +// The only critical timing parameter is the minimum pulse length of the "0" +// Warn or throw error if this timing can not be met with current F_CPU settings. +#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000) +#if w_lowtime>550 + #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" +#elif w_lowtime>450 + #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." + #warning "Please consider a higher clockspeed, if possible" +#endif + +#if w2>0 +#define w2_nops w2 +#else +#define w2_nops 0 +#endif + +#if w3>0 +#define w3_nops w3 +#else +#define w3_nops 0 +#endif + +#define w_nop1 "nop \n\t" +#define w_nop2 "rjmp .+0 \n\t" +#define w_nop4 w_nop2 w_nop2 +#define w_nop8 w_nop4 w_nop4 +#define w_nop16 w_nop8 w_nop8 + +void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) +{ + uint8_t curbyte,ctr,masklo; + uint8_t sreg_prev; + + masklo =~maskhi&ws2812_PORTREG; + maskhi |= ws2812_PORTREG; + sreg_prev=SREG; + cli(); + + while (datlen--) { + curbyte=*data++; + + asm volatile( + " ldi %0,8 \n\t" + "loop%=: \n\t" + " out %2,%3 \n\t" // '1' [01] '0' [01] - re +#if (w1_nops&1) +w_nop1 +#endif +#if (w1_nops&2) +w_nop2 +#endif +#if (w1_nops&4) +w_nop4 +#endif +#if (w1_nops&8) +w_nop8 +#endif +#if (w1_nops&16) +w_nop16 +#endif + " sbrs %1,7 \n\t" // '1' [03] '0' [02] + " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low + " lsl %1 \n\t" // '1' [04] '0' [04] +#if (w2_nops&1) + w_nop1 +#endif +#if (w2_nops&2) + w_nop2 +#endif +#if (w2_nops&4) + w_nop4 +#endif +#if (w2_nops&8) + w_nop8 +#endif +#if (w2_nops&16) + w_nop16 +#endif + " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high +#if (w3_nops&1) +w_nop1 +#endif +#if (w3_nops&2) +w_nop2 +#endif +#if (w3_nops&4) +w_nop4 +#endif +#if (w3_nops&8) +w_nop8 +#endif +#if (w3_nops&16) +w_nop16 +#endif + + " dec %0 \n\t" // '1' [+2] '0' [+2] + " brne loop%=\n\t" // '1' [+3] '0' [+4] + : "=&d" (ctr) + : "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo) + ); + } + + SREG=sreg_prev; +} diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h new file mode 100755 index 0000000000..54eef22d9e --- /dev/null +++ b/quantum/light_ws2812.h @@ -0,0 +1,73 @@ +/* + * light weight WS2812 lib include + * + * Version 2.3 - Nev 29th 2015 + * Author: Tim (cpldcpu@gmail.com) + * + * Please do not change this file! All configuration is handled in "ws2812_config.h" + * + * License: GNU GPL v2 (see License.txt) + + + */ + +#ifndef LIGHT_WS2812_H_ +#define LIGHT_WS2812_H_ + +#include <avr/io.h> +#include <avr/interrupt.h> +//#include "ws2812_config.h" + +/* + * Structure of the LED array + * + * cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106 + * cRGBW: RGBW for SK6812RGBW + */ + +struct cRGB { uint8_t g; uint8_t r; uint8_t b; }; +struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;}; + + + +/* User Interface + * + * Input: + * ledarray: An array of GRB data describing the LED colors + * number_of_leds: The number of LEDs to write + * pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0) + * + * The functions will perform the following actions: + * - Set the data-out pin as output + * - Send out the LED data + * - Wait 50�s to reset the LEDs + */ + +void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds); +void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask); +void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds); + +/* + * Old interface / Internal functions + * + * The functions take a byte-array and send to the data output as WS2812 bitstream. + * The length is the number of bytes to send - three per LED. + */ + +void ws2812_sendarray (uint8_t *array,uint16_t length); +void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask); + + +/* + * Internal defines + */ +#ifndef CONCAT +#define CONCAT(a, b) a ## b +#endif +#ifndef CONCAT_EXP +#define CONCAT_EXP(a, b) CONCAT(a, b) +#endif + +// #define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port) +// #define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port) + +#endif /* LIGHT_WS2812_H_ */ diff --git a/quantum/matrix.c b/quantum/matrix.c new file mode 100644 index 0000000000..0949170255 --- /dev/null +++ b/quantum/matrix.c @@ -0,0 +1,307 @@ +/* +Copyright 2012 Jun Wako +Copyright 2014 Jack Humbert + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <stdint.h> +#include <stdbool.h> +#if defined(__AVR__) +#include <avr/io.h> +#endif +#include "wait.h" +#include "print.h" +#include "debug.h" +#include "util.h" +#include "matrix.h" + +/* Set 0 if debouncing isn't needed */ +/* + * This constant define not debouncing time in msecs, but amount of matrix + * scan loops which should be made to get stable debounced results. + * + * On Ergodox matrix scan rate is relatively low, because of slow I2C. + * Now it's only 317 scans/second, or about 3.15 msec/scan. + * According to Cherry specs, debouncing time is 5 msec. + * + * And so, there is no sense to have DEBOUNCE higher than 2. + */ + +#ifndef DEBOUNCING_DELAY +# define DEBOUNCING_DELAY 5 +#endif +static uint8_t debouncing = DEBOUNCING_DELAY; + +static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; +static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; + +/* matrix state(1:on, 0:off) */ +static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t matrix_debouncing[MATRIX_ROWS]; + +#if DIODE_DIRECTION == ROW2COL + static matrix_row_t matrix_reversed[MATRIX_COLS]; + static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS]; +#endif + +#if MATRIX_COLS > 16 + #define SHIFTER 1UL +#else + #define SHIFTER 1 +#endif + +static matrix_row_t read_cols(void); +static void init_cols(void); +static void unselect_rows(void); +static void select_row(uint8_t row); + +__attribute__ ((weak)) +void matrix_init_quantum(void) { + matrix_init_kb(); +} + +__attribute__ ((weak)) +void matrix_scan_quantum(void) { + matrix_scan_kb(); +} + +__attribute__ ((weak)) +void matrix_init_kb(void) { + matrix_init_user(); +} + +__attribute__ ((weak)) +void matrix_scan_kb(void) { + matrix_scan_user(); +} + +__attribute__ ((weak)) +void matrix_init_user(void) { +} + +__attribute__ ((weak)) +void matrix_scan_user(void) { +} + +inline +uint8_t matrix_rows(void) { + return MATRIX_ROWS; +} + +inline +uint8_t matrix_cols(void) { + return MATRIX_COLS; +} + +// void matrix_power_up(void) { +// #if DIODE_DIRECTION == COL2ROW +// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { +// /* DDRxn */ +// _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF); +// toggle_row(r); +// } +// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { +// /* PORTxn */ +// _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF); +// } +// #else +// for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) { +// /* DDRxn */ +// _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF); +// toggle_col(c); +// } +// for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) { +// /* PORTxn */ +// _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF); +// } +// #endif +// } + +void matrix_init(void) { + // To use PORTF disable JTAG with writing JTD bit twice within four cycles. + #ifdef __AVR_ATmega32U4__ + MCUCR |= _BV(JTD); + MCUCR |= _BV(JTD); + #endif + + // initialize row and col + unselect_rows(); + init_cols(); + + // initialize matrix state: all keys off + for (uint8_t i=0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + matrix_debouncing[i] = 0; + } + + matrix_init_quantum(); +} + +uint8_t matrix_scan(void) +{ + +#if DIODE_DIRECTION == COL2ROW + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + select_row(i); + wait_us(30); // without this wait read unstable value. + matrix_row_t cols = read_cols(); + if (matrix_debouncing[i] != cols) { + matrix_debouncing[i] = cols; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); + } + debouncing = DEBOUNCING_DELAY; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + wait_us(1); + } else { + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = matrix_debouncing[i]; + } + } + } +#else + for (uint8_t i = 0; i < MATRIX_COLS; i++) { + select_row(i); + wait_us(30); // without this wait read unstable value. + matrix_row_t rows = read_cols(); + if (matrix_reversed_debouncing[i] != rows) { + matrix_reversed_debouncing[i] = rows; + if (debouncing) { + debug("bounce!: "); debug_hex(debouncing); debug("\n"); + } + debouncing = DEBOUNCING_DELAY; + } + unselect_rows(); + } + + if (debouncing) { + if (--debouncing) { + wait_us(1); + } else { + for (uint8_t i = 0; i < MATRIX_COLS; i++) { + matrix_reversed[i] = matrix_reversed_debouncing[i]; + } + } + } + for (uint8_t y = 0; y < MATRIX_ROWS; y++) { + matrix_row_t row = 0; + for (uint8_t x = 0; x < MATRIX_COLS; x++) { + row |= ((matrix_reversed[x] & (1<<y)) >> y) << x; + } + matrix[y] = row; + } +#endif + + matrix_scan_quantum(); + + return 1; +} + +bool matrix_is_modified(void) +{ + if (debouncing) return false; + return true; +} + +inline +bool matrix_is_on(uint8_t row, uint8_t col) +{ + return (matrix[row] & ((matrix_row_t)1<col)); +} + +inline +matrix_row_t matrix_get_row(uint8_t row) +{ + return matrix[row]; +} + +void matrix_print(void) +{ + print("\nr/c 0123456789ABCDEF\n"); + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); print(": "); + pbin_reverse16(matrix_get_row(row)); + print("\n"); + } +} + +uint8_t matrix_key_count(void) +{ + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += bitpop16(matrix[i]); + } + return count; +} + +static void init_cols(void) +{ +#if DIODE_DIRECTION == COL2ROW + for(int x = 0; x < MATRIX_COLS; x++) { + int pin = col_pins[x]; +#else + for(int x = 0; x < MATRIX_ROWS; x++) { + int pin = row_pins[x]; +#endif + _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); + _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); + } +} + +static matrix_row_t read_cols(void) +{ + matrix_row_t result = 0; + +#if DIODE_DIRECTION == COL2ROW + for(int x = 0; x < MATRIX_COLS; x++) { + int pin = col_pins[x]; +#else + for(int x = 0; x < MATRIX_ROWS; x++) { + int pin = row_pins[x]; +#endif + result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x); + } + return result; +} + +static void unselect_rows(void) +{ +#if DIODE_DIRECTION == COL2ROW + for(int x = 0; x < MATRIX_ROWS; x++) { + int pin = row_pins[x]; +#else + for(int x = 0; x < MATRIX_COLS; x++) { + int pin = col_pins[x]; +#endif + _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); + _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); + } +} + +static void select_row(uint8_t row) +{ + +#if DIODE_DIRECTION == COL2ROW + int pin = row_pins[row]; +#else + int pin = col_pins[row]; +#endif + _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); + _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); +} diff --git a/quantum/process_keycode/process_chording.c b/quantum/process_keycode/process_chording.c new file mode 100644 index 0000000000..d7814629f3 --- /dev/null +++ b/quantum/process_keycode/process_chording.c @@ -0,0 +1,60 @@ +#include "process_chording.h" + +bool keys_chord(uint8_t keys[]) { + uint8_t keys_size = sizeof(keys)/sizeof(keys[0]); + bool pass = true; + uint8_t in = 0; + for (uint8_t i = 0; i < chord_key_count; i++) { + bool found = false; + for (uint8_t j = 0; j < keys_size; j++) { + if (chord_keys[i] == (keys[j] & 0xFF)) { + in++; // detects key in chord + found = true; + break; + } + } + if (found) + continue; + if (chord_keys[i] != 0) { + pass = false; // makes sure rest are blank + } + } + return (pass && (in == keys_size)); +} + +bool process_chording(uint16_t keycode, keyrecord_t *record) { + if (keycode >= QK_CHORDING && keycode <= QK_CHORDING_MAX) { + if (record->event.pressed) { + if (!chording) { + chording = true; + for (uint8_t i = 0; i < CHORDING_MAX; i++) + chord_keys[i] = 0; + chord_key_count = 0; + chord_key_down = 0; + } + chord_keys[chord_key_count] = (keycode & 0xFF); + chord_key_count++; + chord_key_down++; + return false; + } else { + if (chording) { + chord_key_down--; + if (chord_key_down == 0) { + chording = false; + // Chord Dictionary + if (keys_chord((uint8_t[]){KC_ENTER, KC_SPACE})) { + register_code(KC_A); + unregister_code(KC_A); + return false; + } + for (uint8_t i = 0; i < chord_key_count; i++) { + register_code(chord_keys[i]); + unregister_code(chord_keys[i]); + return false; + } + } + } + } + } + return true; +}
\ 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 0000000000..49c97db3bc --- /dev/null +++ b/quantum/process_keycode/process_chording.h @@ -0,0 +1,16 @@ +#ifndef PROCESS_CHORDING_H +#define PROCESS_CHORDING_H + +#include "quantum.h" + +// Chording stuff +#define CHORDING_MAX 4 +bool chording = false; + +uint8_t chord_keys[CHORDING_MAX] = {0}; +uint8_t chord_key_count = 0; +uint8_t chord_key_down = 0; + +bool process_chording(uint16_t keycode, keyrecord_t *record); + +#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 0000000000..e53d221e75 --- /dev/null +++ b/quantum/process_keycode/process_leader.c @@ -0,0 +1,38 @@ +#include "process_leader.h" + +__attribute__ ((weak)) +void leader_start(void) {} + +__attribute__ ((weak)) +void leader_end(void) {} + +// Leader key stuff +bool leading = false; +uint16_t leader_time = 0; + +uint16_t leader_sequence[5] = {0, 0, 0, 0, 0}; +uint8_t leader_sequence_size = 0; + +bool process_leader(uint16_t keycode, keyrecord_t *record) { + // Leader key set-up + if (record->event.pressed) { + if (!leading && keycode == KC_LEAD) { + leader_start(); + leading = true; + leader_time = timer_read(); + leader_sequence_size = 0; + leader_sequence[0] = 0; + leader_sequence[1] = 0; + leader_sequence[2] = 0; + leader_sequence[3] = 0; + leader_sequence[4] = 0; + return false; + } + if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) { + leader_sequence[leader_sequence_size] = keycode; + leader_sequence_size++; + return false; + } + } + return true; +}
\ 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 0000000000..c83db8abbd --- /dev/null +++ b/quantum/process_keycode/process_leader.h @@ -0,0 +1,23 @@ +#ifndef PROCESS_LEADER_H +#define PROCESS_LEADER_H + +#include "quantum.h" + +bool process_leader(uint16_t keycode, keyrecord_t *record); + +void leader_start(void); +void leader_end(void); + +#ifndef LEADER_TIMEOUT + #define LEADER_TIMEOUT 200 +#endif +#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) +#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) +#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) +#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) +#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)) + +#define LEADER_EXTERNS() extern bool leading; extern uint16_t leader_time; extern uint16_t leader_sequence[5]; extern uint8_t leader_sequence_size +#define LEADER_DICTIONARY() if (leading && timer_elapsed(leader_time) > LEADER_TIMEOUT) + +#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 0000000000..d6ab9c6264 --- /dev/null +++ b/quantum/process_keycode/process_midi.c @@ -0,0 +1,66 @@ +#include "process_midi.h" + +bool midi_activated = false; +uint8_t starting_note = 0x0C; +int offset = 7; + +bool process_midi(uint16_t keycode, keyrecord_t *record) { + if (keycode == MI_ON && record->event.pressed) { + midi_activated = true; + music_scale_user(); + return false; + } + + if (keycode == MI_OFF && record->event.pressed) { + midi_activated = false; + midi_send_cc(&midi_device, 0, 0x7B, 0); + return false; + } + + if (midi_activated) { + if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) { + if (record->event.pressed) { + starting_note++; // Change key + midi_send_cc(&midi_device, 0, 0x7B, 0); + } + return false; + } + if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) { + if (record->event.pressed) { + starting_note--; // Change key + midi_send_cc(&midi_device, 0, 0x7B, 0); + } + return false; + } + if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { + offset++; // Change scale + midi_send_cc(&midi_device, 0, 0x7B, 0); + return false; + } + if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { + offset--; // Change scale + midi_send_cc(&midi_device, 0, 0x7B, 0); + return false; + } + // basic + // uint8_t note = (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row); + // advanced + // uint8_t note = (starting_note + record->event.key.col + offset)+12*(MATRIX_ROWS - record->event.key.row); + // guitar + uint8_t note = (starting_note + record->event.key.col + offset)+5*(MATRIX_ROWS - record->event.key.row); + // violin + // uint8_t note = (starting_note + record->event.key.col + offset)+7*(MATRIX_ROWS - record->event.key.row); + + if (record->event.pressed) { + // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127); + midi_send_noteon(&midi_device, 0, note, 127); + } else { + // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127); + midi_send_noteoff(&midi_device, 0, note, 127); + } + + if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through + return false; + } + return true; +}
\ 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 0000000000..acd4fc1b16 --- /dev/null +++ b/quantum/process_keycode/process_midi.h @@ -0,0 +1,207 @@ +#ifndef PROCESS_MIDI_H +#define PROCESS_MIDI_H + +#include "quantum.h" + +bool process_midi(uint16_t keycode, keyrecord_t *record); + +#define MIDI(n) ((n) | 0x6000) +#define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000 + +#define CHNL(note, channel) (note + (channel << 8)) + +#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), \ + 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ + 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ + 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ + 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } + +#define N_CN1 (0x600C + (12 * -1) + 0 ) +#define N_CN1S (0x600C + (12 * -1) + 1 ) +#define N_DN1F (0x600C + (12 * -1) + 1 ) +#define N_DN1 (0x600C + (12 * -1) + 2 ) +#define N_DN1S (0x600C + (12 * -1) + 3 ) +#define N_EN1F (0x600C + (12 * -1) + 3 ) +#define N_EN1 (0x600C + (12 * -1) + 4 ) +#define N_FN1 (0x600C + (12 * -1) + 5 ) +#define N_FN1S (0x600C + (12 * -1) + 6 ) +#define N_GN1F (0x600C + (12 * -1) + 6 ) +#define N_GN1 (0x600C + (12 * -1) + 7 ) +#define N_GN1S (0x600C + (12 * -1) + 8 ) +#define N_AN1F (0x600C + (12 * -1) + 8 ) +#define N_AN1 (0x600C + (12 * -1) + 9 ) +#define N_AN1S (0x600C + (12 * -1) + 10) +#define N_BN1F (0x600C + (12 * -1) + 10) +#define N_BN1 (0x600C + (12 * -1) + 11) +#define N_C0 (0x600C + (12 * 0) + 0 ) +#define N_C0S (0x600C + (12 * 0) + 1 ) +#define N_D0F (0x600C + (12 * 0) + 1 ) +#define N_D0 (0x600C + (12 * 0) + 2 ) +#define N_D0S (0x600C + (12 * 0) + 3 ) +#define N_E0F (0x600C + (12 * 0) + 3 ) +#define N_E0 (0x600C + (12 * 0) + 4 ) +#define N_F0 (0x600C + (12 * 0) + 5 ) +#define N_F0S (0x600C + (12 * 0) + 6 ) +#define N_G0F (0x600C + (12 * 0) + 6 ) +#define N_G0 (0x600C + (12 * 0) + 7 ) +#define N_G0S (0x600C + (12 * 0) + 8 ) +#define N_A0F (0x600C + (12 * 0) + 8 ) +#define N_A0 (0x600C + (12 * 0) + 9 ) +#define N_A0S (0x600C + (12 * 0) + 10) +#define N_B0F (0x600C + (12 * 0) + 10) +#define N_B0 (0x600C + (12 * 0) + 11) +#define N_C1 (0x600C + (12 * 1) + 0 ) +#define N_C1S (0x600C + (12 * 1) + 1 ) +#define N_D1F (0x600C + (12 * 1) + 1 ) +#define N_D1 (0x600C + (12 * 1) + 2 ) +#define N_D1S (0x600C + (12 * 1) + 3 ) +#define N_E1F (0x600C + (12 * 1) + 3 ) +#define N_E1 (0x600C + (12 * 1) + 4 ) +#define N_F1 (0x600C + (12 * 1) + 5 ) +#define N_F1S (0x600C + (12 * 1) + 6 ) +#define N_G1F (0x600C + (12 * 1) + 6 ) +#define N_G1 (0x600C + (12 * 1) + 7 ) +#define N_G1S (0x600C + (12 * 1) + 8 ) +#define N_A1F (0x600C + (12 * 1) + 8 ) +#define N_A1 (0x600C + (12 * 1) + 9 ) +#define N_A1S (0x600C + (12 * 1) + 10) +#define N_B1F (0x600C + (12 * 1) + 10) +#define N_B1 (0x600C + (12 * 1) + 11) +#define N_C2 (0x600C + (12 * 2) + 0 ) +#define N_C2S (0x600C + (12 * 2) + 1 ) +#define N_D2F (0x600C + (12 * 2) + 1 ) +#define N_D2 (0x600C + (12 * 2) + 2 ) +#define N_D2S (0x600C + (12 * 2) + 3 ) +#define N_E2F (0x600C + (12 * 2) + 3 ) +#define N_E2 (0x600C + (12 * 2) + 4 ) +#define N_F2 (0x600C + (12 * 2) + 5 ) +#define N_F2S (0x600C + (12 * 2) + 6 ) +#define N_G2F (0x600C + (12 * 2) + 6 ) +#define N_G2 (0x600C + (12 * 2) + 7 ) +#define N_G2S (0x600C + (12 * 2) + 8 ) +#define N_A2F (0x600C + (12 * 2) + 8 ) +#define N_A2 (0x600C + (12 * 2) + 9 ) +#define N_A2S (0x600C + (12 * 2) + 10) +#define N_B2F (0x600C + (12 * 2) + 10) +#define N_B2 (0x600C + (12 * 2) + 11) +#define N_C3 (0x600C + (12 * 3) + 0 ) +#define N_C3S (0x600C + (12 * 3) + 1 ) +#define N_D3F (0x600C + (12 * 3) + 1 ) +#define N_D3 (0x600C + (12 * 3) + 2 ) +#define N_D3S (0x600C + (12 * 3) + 3 ) +#define N_E3F (0x600C + (12 * 3) + 3 ) +#define N_E3 (0x600C + (12 * 3) + 4 ) +#define N_F3 (0x600C + (12 * 3) + 5 ) +#define N_F3S (0x600C + (12 * 3) + 6 ) +#define N_G3F (0x600C + (12 * 3) + 6 ) +#define N_G3 (0x600C + (12 * 3) + 7 ) +#define N_G3S (0x600C + (12 * 3) + 8 ) +#define N_A3F (0x600C + (12 * 3) + 8 ) +#define N_A3 (0x600C + (12 * 3) + 9 ) +#define N_A3S (0x600C + (12 * 3) + 10) +#define N_B3F (0x600C + (12 * 3) + 10) +#define N_B3 (0x600C + (12 * 3) + 11) +#define N_C4 (0x600C + (12 * 4) + 0 ) +#define N_C4S (0x600C + (12 * 4) + 1 ) +#define N_D4F (0x600C + (12 * 4) + 1 ) +#define N_D4 (0x600C + (12 * 4) + 2 ) +#define N_D4S (0x600C + (12 * 4) + 3 ) +#define N_E4F (0x600C + (12 * 4) + 3 ) +#define N_E4 (0x600C + (12 * 4) + 4 ) +#define N_F4 (0x600C + (12 * 4) + 5 ) +#define N_F4S (0x600C + (12 * 4) + 6 ) +#define N_G4F (0x600C + (12 * 4) + 6 ) +#define N_G4 (0x600C + (12 * 4) + 7 ) +#define N_G4S (0x600C + (12 * 4) + 8 ) +#define N_A4F (0x600C + (12 * 4) + 8 ) +#define N_A4 (0x600C + (12 * 4) + 9 ) +#define N_A4S (0x600C + (12 * 4) + 10) +#define N_B4F (0x600C + (12 * 4) + 10) +#define N_B4 (0x600C + (12 * 4) + 11) +#define N_C5 (0x600C + (12 * 5) + 0 ) +#define N_C5S (0x600C + (12 * 5) + 1 ) +#define N_D5F (0x600C + (12 * 5) + 1 ) +#define N_D5 (0x600C + (12 * 5) + 2 ) +#define N_D5S (0x600C + (12 * 5) + 3 ) +#define N_E5F (0x600C + (12 * 5) + 3 ) +#define N_E5 (0x600C + (12 * 5) + 4 ) +#define N_F5 (0x600C + (12 * 5) + 5 ) +#define N_F5S (0x600C + (12 * 5) + 6 ) +#define N_G5F (0x600C + (12 * 5) + 6 ) +#define N_G5 (0x600C + (12 * 5) + 7 ) +#define N_G5S (0x600C + (12 * 5) + 8 ) +#define N_A5F (0x600C + (12 * 5) + 8 ) +#define N_A5 (0x600C + (12 * 5) + 9 ) +#define N_A5S (0x600C + (12 * 5) + 10) +#define N_B5F (0x600C + (12 * 5) + 10) +#define N_B5 (0x600C + (12 * 5) + 11) +#define N_C6 (0x600C + (12 * 6) + 0 ) +#define N_C6S (0x600C + (12 * 6) + 1 ) +#define N_D6F (0x600C + (12 * 6) + 1 ) +#define N_D6 (0x600C + (12 * 6) + 2 ) +#define N_D6S (0x600C + (12 * 6) + 3 ) +#define N_E6F (0x600C + (12 * 6) + 3 ) +#define N_E6 (0x600C + (12 * 6) + 4 ) +#define N_F6 (0x600C + (12 * 6) + 5 ) +#define N_F6S (0x600C + (12 * 6) + 6 ) +#define N_G6F (0x600C + (12 * 6) + 6 ) +#define N_G6 (0x600C + (12 * 6) + 7 ) +#define N_G6S (0x600C + (12 * 6) + 8 ) +#define N_A6F (0x600C + (12 * 6) + 8 ) +#define N_A6 (0x600C + (12 * 6) + 9 ) +#define N_A6S (0x600C + (12 * 6) + 10) +#define N_B6F (0x600C + (12 * 6) + 10) +#define N_B6 (0x600C + (12 * 6) + 11) +#define N_C7 (0x600C + (12 * 7) + 0 ) +#define N_C7S (0x600C + (12 * 7) + 1 ) +#define N_D7F (0x600C + (12 * 7) + 1 ) +#define N_D7 (0x600C + (12 * 7) + 2 ) +#define N_D7S (0x600C + (12 * 7) + 3 ) +#define N_E7F (0x600C + (12 * 7) + 3 ) +#define N_E7 (0x600C + (12 * 7) + 4 ) +#define N_F7 (0x600C + (12 * 7) + 5 ) +#define N_F7S (0x600C + (12 * 7) + 6 ) +#define N_G7F (0x600C + (12 * 7) + 6 ) +#define N_G7 (0x600C + (12 * 7) + 7 ) +#define N_G7S (0x600C + (12 * 7) + 8 ) +#define N_A7F (0x600C + (12 * 7) + 8 ) +#define N_A7 (0x600C + (12 * 7) + 9 ) +#define N_A7S (0x600C + (12 * 7) + 10) +#define N_B7F (0x600C + (12 * 7) + 10) +#define N_B7 (0x600C + (12 * 7) + 11) +#define N_C8 (0x600C + (12 * 8) + 0 ) +#define N_C8S (0x600C + (12 * 8) + 1 ) +#define N_D8F (0x600C + (12 * 8) + 1 ) +#define N_D8 (0x600C + (12 * 8) + 2 ) +#define N_D8S (0x600C + (12 * 8) + 3 ) +#define N_E8F (0x600C + (12 * 8) + 3 ) +#define N_E8 (0x600C + (12 * 8) + 4 ) +#define N_F8 (0x600C + (12 * 8) + 5 ) +#define N_F8S (0x600C + (12 * 8) + 6 ) +#define N_G8F (0x600C + (12 * 8) + 6 ) +#define N_G8 (0x600C + (12 * 8) + 7 ) +#define N_G8S (0x600C + (12 * 8) + 8 ) +#define N_A8F (0x600C + (12 * 8) + 8 ) +#define N_A8 (0x600C + (12 * 8) + 9 ) +#define N_A8S (0x600C + (12 * 8) + 10) +#define N_B8F (0x600C + (12 * 8) + 10) +#define N_B8 (0x600C + (12 * 8) + 11) +#define N_C8 (0x600C + (12 * 8) + 0 ) +#define N_C8S (0x600C + (12 * 8) + 1 ) +#define N_D8F (0x600C + (12 * 8) + 1 ) +#define N_D8 (0x600C + (12 * 8) + 2 ) +#define N_D8S (0x600C + (12 * 8) + 3 ) +#define N_E8F (0x600C + (12 * 8) + 3 ) +#define N_E8 (0x600C + (12 * 8) + 4 ) +#define N_F8 (0x600C + (12 * 8) + 5 ) +#define N_F8S (0x600C + (12 * 8) + 6 ) +#define N_G8F (0x600C + (12 * 8) + 6 ) +#define N_G8 (0x600C + (12 * 8) + 7 ) +#define N_G8S (0x600C + (12 * 8) + 8 ) +#define N_A8F (0x600C + (12 * 8) + 8 ) +#define N_A8 (0x600C + (12 * 8) + 9 ) +#define N_A8S (0x600C + (12 * 8) + 10) +#define N_B8F (0x600C + (12 * 8) + 10) +#define N_B8 (0x600C + (12 * 8) + 11) + +#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 0000000000..c8f3ddb900 --- /dev/null +++ b/quantum/process_keycode/process_music.c @@ -0,0 +1,171 @@ +#include "process_music.h" + +bool music_activated = false; +uint8_t starting_note = 0x0C; +int offset = 7; + +// music sequencer +static bool music_sequence_recording = false; +static bool music_sequence_playing = false; +static float music_sequence[16] = {0}; +static uint8_t music_sequence_count = 0; +static uint8_t music_sequence_position = 0; + +static uint16_t music_sequence_timer = 0; +static uint16_t music_sequence_interval = 100; + +bool process_music(uint16_t keycode, keyrecord_t *record) { + + if (keycode == AU_ON && record->event.pressed) { + audio_on(); + return false; + } + + if (keycode == AU_OFF && record->event.pressed) { + audio_off(); + return false; + } + + if (keycode == AU_TOG && record->event.pressed) { + if (is_audio_on()) + { + audio_off(); + } + else + { + audio_on(); + } + return false; + } + + if (keycode == MU_ON && record->event.pressed) { + music_on(); + return false; + } + + if (keycode == MU_OFF && record->event.pressed) { + music_off(); + return false; + } + + if (keycode == MU_TOG && record->event.pressed) { + if (music_activated) + { + music_off(); + } + else + { + music_on(); + } + return false; + } + + if (keycode == MUV_IN && record->event.pressed) { + voice_iterate(); + music_scale_user(); + return false; + } + + if (keycode == MUV_DE && record->event.pressed) { + voice_deiterate(); + music_scale_user(); + return false; + } + + if (music_activated) { + + if (keycode == KC_LCTL && record->event.pressed) { // Start recording + stop_all_notes(); + music_sequence_recording = true; + music_sequence_playing = false; + music_sequence_count = 0; + return false; + } + + if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing + stop_all_notes(); + music_sequence_recording = false; + music_sequence_playing = false; + return false; + } + + if (keycode == KC_LGUI && record->event.pressed) { // Start playing + stop_all_notes(); + music_sequence_recording = false; + music_sequence_playing = true; + music_sequence_position = 0; + music_sequence_timer = 0; + return false; + } + + if (keycode == KC_UP) { + if (record->event.pressed) + music_sequence_interval-=10; + return false; + } + + if (keycode == KC_DOWN) { + if (record->event.pressed) + music_sequence_interval+=10; + return false; + } + + 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)); + if (record->event.pressed) { + play_note(freq, 0xF); + if (music_sequence_recording) { + music_sequence[music_sequence_count] = freq; + music_sequence_count++; + } + } else { + stop_note(freq); + } + + if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through + return false; + } + return true; +} + +bool is_music_on(void) { + return (music_activated != 0); +} + +void music_toggle(void) { + if (!music_activated) { + music_on(); + } else { + music_off(); + } +} + +void music_on(void) { + music_activated = 1; + music_on_user(); +} + +void music_off(void) { + music_activated = 0; + stop_all_notes(); +} + + +__attribute__ ((weak)) +void music_on_user() {} + +__attribute__ ((weak)) +void audio_on_user() {} + +__attribute__ ((weak)) +void music_scale_user() {} + +void matrix_scan_music(void) { + if (music_sequence_playing) { + if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) { + music_sequence_timer = timer_read(); + stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]); + play_note(music_sequence[music_sequence_position], 0xF); + music_sequence_position = (music_sequence_position + 1) % music_sequence_count; + } + } +} diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h new file mode 100644 index 0000000000..318b3e3875 --- /dev/null +++ b/quantum/process_keycode/process_music.h @@ -0,0 +1,27 @@ +#ifndef PROCESS_MUSIC_H +#define PROCESS_MUSIC_H + +#include "quantum.h" + +bool process_music(uint16_t keycode, keyrecord_t *record); + +bool is_music_on(void); +void music_toggle(void); +void music_on(void); +void music_off(void); + +void audio_on_user(void); +void music_on_user(void); +void music_scale_user(void); + +void matrix_scan_music(void); + +#ifndef SCALE +#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), \ + 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ + 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ + 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ + 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } +#endif + +#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 0000000000..9b172e1b6c --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.c @@ -0,0 +1,90 @@ +#include "quantum.h" + +static qk_tap_dance_state_t qk_tap_dance_state; + +static void _process_tap_dance_action_pair (qk_tap_dance_state_t *state, + uint16_t kc1, uint16_t kc2) { + uint16_t kc; + + if (state->count == 0) + return; + + kc = (state->count == 1) ? kc1 : kc2; + + register_code (kc); + unregister_code (kc); + + if (state->count >= 2) { + reset_tap_dance (state); + } +} + +static void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, + qk_tap_dance_user_fn_t fn) +{ + fn(state); +} + +void process_tap_dance_action (uint16_t keycode) +{ + uint16_t idx = keycode - QK_TAP_DANCE; + qk_tap_dance_action_t action; + + action = tap_dance_actions[idx]; + + switch (action.type) { + case QK_TAP_DANCE_TYPE_PAIR: + _process_tap_dance_action_pair (&qk_tap_dance_state, + action.pair.kc1, action.pair.kc2); + break; + case QK_TAP_DANCE_TYPE_FN: + _process_tap_dance_action_fn (&qk_tap_dance_state, action.fn); + break; + + default: + break; + } +} + +bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { + bool r = true; + + switch(keycode) { + case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: + if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) { + process_tap_dance_action (qk_tap_dance_state.keycode); + } else { + r = false; + } + + if (record->event.pressed) { + qk_tap_dance_state.keycode = keycode; + qk_tap_dance_state.timer = timer_read (); + qk_tap_dance_state.count++; + } + break; + + default: + if (qk_tap_dance_state.keycode) { + process_tap_dance_action (qk_tap_dance_state.keycode); + + reset_tap_dance (&qk_tap_dance_state); + } + break; + } + + return r; +} + +void matrix_scan_tap_dance () { + if (qk_tap_dance_state.keycode && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) { + process_tap_dance_action (qk_tap_dance_state.keycode); + + reset_tap_dance (&qk_tap_dance_state); + } +} + +void reset_tap_dance (qk_tap_dance_state_t *state) { + state->keycode = 0; + state->count = 0; +} diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h new file mode 100644 index 0000000000..b9d7c7fcf4 --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.h @@ -0,0 +1,62 @@ +#ifndef PROCESS_TAP_DANCE_H +#define PROCESS_TAP_DANCE_H + +#ifdef TAP_DANCE_ENABLE + +#include <stdbool.h> +#include <inttypes.h> + +typedef struct +{ + uint8_t count; + uint16_t keycode; + uint16_t timer; +} qk_tap_dance_state_t; + +#define TD(n) (QK_TAP_DANCE + n) + +typedef enum +{ + QK_TAP_DANCE_TYPE_PAIR, + QK_TAP_DANCE_TYPE_FN, +} qk_tap_dance_type_t; + +typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state); + +typedef struct +{ + qk_tap_dance_type_t type; + union { + struct { + uint16_t kc1; + uint16_t kc2; + } pair; + qk_tap_dance_user_fn_t fn; + }; +} qk_tap_dance_action_t; + +#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \ + .type = QK_TAP_DANCE_TYPE_PAIR, \ + .pair = { kc1, kc2 } \ + } + +#define ACTION_TAP_DANCE_FN(user_fn) { \ + .type = QK_TAP_DANCE_TYPE_FN, \ + .fn = user_fn \ + } + +extern const qk_tap_dance_action_t tap_dance_actions[]; + +/* To be used internally */ + +bool process_tap_dance(uint16_t keycode, keyrecord_t *record); +void matrix_scan_tap_dance (void); +void reset_tap_dance (qk_tap_dance_state_t *state); + +#else + +#define TD(n) KC_NO + +#endif + +#endif diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c new file mode 100644 index 0000000000..ad5d7f86b7 --- /dev/null +++ b/quantum/process_keycode/process_unicode.c @@ -0,0 +1,57 @@ +#include "process_unicode.h" + +static uint8_t input_mode; + +uint16_t hex_to_keycode(uint8_t hex) +{ + if (hex == 0x0) { + return KC_0; + } else if (hex < 0xA) { + return KC_1 + (hex - 0x1); + } else { + return KC_A + (hex - 0xA); + } +} + +void set_unicode_mode(uint8_t os_target) +{ + input_mode = os_target; +} + +bool process_unicode(uint16_t keycode, keyrecord_t *record) { + if (keycode > QK_UNICODE && record->event.pressed) { + uint16_t unicode = keycode & 0x7FFF; + switch(input_mode) { + case UC_OSX: + register_code(KC_LALT); + break; + case UC_LNX: + register_code(KC_LCTL); + register_code(KC_LSFT); + register_code(KC_U); + unregister_code(KC_U); + break; + case UC_WIN: + register_code(KC_LALT); + register_code(KC_PPLS); + unregister_code(KC_PPLS); + break; + } + for(int i = 3; i >= 0; i--) { + uint8_t digit = ((unicode >> (i*4)) & 0xF); + register_code(hex_to_keycode(digit)); + unregister_code(hex_to_keycode(digit)); + } + switch(input_mode) { + case UC_OSX: + case UC_WIN: + unregister_code(KC_LALT); + break; + case UC_LNX: + unregister_code(KC_LCTL); + unregister_code(KC_LSFT); + break; + } + } + return true; +}
\ 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 0000000000..ca17f8f669 --- /dev/null +++ b/quantum/process_keycode/process_unicode.h @@ -0,0 +1,122 @@ +#ifndef PROCESS_UNICODE_H +#define PROCESS_UNICODE_H + +#include "quantum.h" + +#define UC_OSX 0 +#define UC_LNX 1 +#define UC_WIN 2 +#define UC_BSD 3 + +void set_unicode_input_mode(uint8_t os_target); + +bool process_unicode(uint16_t keycode, keyrecord_t *record); + +#define UC_BSPC UC(0x0008) + +#define UC_SPC UC(0x0020) + +#define UC_EXLM UC(0x0021) +#define UC_DQUT UC(0x0022) +#define UC_HASH UC(0x0023) +#define UC_DLR UC(0x0024) +#define UC_PERC UC(0x0025) +#define UC_AMPR UC(0x0026) +#define UC_QUOT UC(0x0027) +#define UC_LPRN UC(0x0028) +#define UC_RPRN UC(0x0029) +#define UC_ASTR UC(0x002A) +#define UC_PLUS UC(0x002B) +#define UC_COMM UC(0x002C) +#define UC_DASH UC(0x002D) +#define UC_DOT UC(0x002E) +#define UC_SLSH UC(0x002F) + +#define UC_0 UC(0x0030) +#define UC_1 UC(0x0031) +#define UC_2 UC(0x0032) +#define UC_3 UC(0x0033) +#define UC_4 UC(0x0034) +#define UC_5 UC(0x0035) +#define UC_6 UC(0x0036) +#define UC_7 UC(0x0037) +#define UC_8 UC(0x0038) +#define UC_9 UC(0x0039) + +#define UC_COLN UC(0x003A) +#define UC_SCLN UC(0x003B) +#define UC_LT UC(0x003C) +#define UC_EQL UC(0x003D) +#define UC_GT UC(0x003E) +#define UC_QUES UC(0x003F) +#define UC_AT UC(0x0040) + +#define UC_A UC(0x0041) +#define UC_B UC(0x0042) +#define UC_C UC(0x0043) +#define UC_D UC(0x0044) +#define UC_E UC(0x0045) +#define UC_F UC(0x0046) +#define UC_G UC(0x0047) +#define UC_H UC(0x0048) +#define UC_I UC(0x0049) +#define UC_J UC(0x004A) +#define UC_K UC(0x004B) +#define UC_L UC(0x004C) +#define UC_M UC(0x004D) +#define UC_N UC(0x004E) +#define UC_O UC(0x004F) +#define UC_P UC(0x0050) +#define UC_Q UC(0x0051) +#define UC_R UC(0x0052) +#define UC_S UC(0x0053) +#define UC_T UC(0x0054) +#define UC_U UC(0x0055) +#define UC_V UC(0x0056) +#define UC_W UC(0x0057) +#define UC_X UC(0x0058) +#define UC_Y UC(0x0059) +#define UC_Z UC(0x005A) + +#define UC_LBRC UC(0x005B) +#define UC_BSLS UC(0x005C) +#define UC_RBRC UC(0x005D) +#define UC_CIRM UC(0x005E) +#define UC_UNDR UC(0x005F) + +#define UC_GRV UC(0x0060) + +#define UC_a UC(0x0061) +#define UC_b UC(0x0062) +#define UC_c UC(0x0063) +#define UC_d UC(0x0064) +#define UC_e UC(0x0065) +#define UC_f UC(0x0066) +#define UC_g UC(0x0067) +#define UC_h UC(0x0068) +#define UC_i UC(0x0069) +#define UC_j UC(0x006A) +#define UC_k UC(0x006B) +#define UC_l UC(0x006C) +#define UC_m UC(0x006D) +#define UC_n UC(0x006E) +#define UC_o UC(0x006F) +#define UC_p UC(0x0070) +#define UC_q UC(0x0071) +#define UC_r UC(0x0072) +#define UC_s UC(0x0073) +#define UC_t UC(0x0074) +#define UC_u UC(0x0075) +#define UC_v UC(0x0076) +#define UC_w UC(0x0077) +#define UC_x UC(0x0078) +#define UC_y UC(0x0079) +#define UC_z UC(0x007A) + +#define UC_LCBR UC(0x007B) +#define UC_PIPE UC(0x007C) +#define UC_RCBR UC(0x007D) +#define UC_TILD UC(0x007E) +#define UC_DEL UC(0x007F) + +#endif
\ No newline at end of file diff --git a/quantum/quantum.c b/quantum/quantum.c new file mode 100644 index 0000000000..d59bd5a3f8 --- /dev/null +++ b/quantum/quantum.c @@ -0,0 +1,717 @@ +#include "quantum.h" + +__attribute__ ((weak)) +bool process_action_kb(keyrecord_t *record) { + return true; +} + +__attribute__ ((weak)) +bool process_record_kb(uint16_t keycode, keyrecord_t *record) { + return process_record_user(keycode, record); +} + +__attribute__ ((weak)) +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + return true; +} + +// Shift / paren setup + +#ifndef LSPO_KEY + #define LSPO_KEY KC_9 +#endif +#ifndef RSPC_KEY + #define RSPC_KEY KC_0 +#endif + +static bool shift_interrupted[2] = {0, 0}; + +bool process_record_quantum(keyrecord_t *record) { + + /* This gets the keycode from the key pressed */ + keypos_t key = record->event.key; + uint16_t keycode; + + #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) + uint8_t layer; + + if (record->event.pressed) { + layer = layer_switch_get_layer(key); + update_source_layers_cache(key, layer); + } else { + layer = read_source_layers_cache(key); + } + keycode = keymap_key_to_keycode(layer, key); + #else + keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key); + #endif + + // This is how you use actions here + // if (keycode == KC_LEAD) { + // action_t action; + // action.code = ACTION_DEFAULT_LAYER_SET(0); + // process_action(record, action); + // return false; + // } + + if (!( + process_record_kb(keycode, record) && + #ifdef MIDI_ENABLE + process_midi(keycode, record) && + #endif + #ifdef AUDIO_ENABLE + process_music(keycode, record) && + #endif + #ifdef TAP_DANCE_ENABLE + process_tap_dance(keycode, record) && + #endif + #ifndef DISABLE_LEADER + process_leader(keycode, record) && + #endif + #ifndef DISABLE_CHORDING + process_chording(keycode, record) && + #endif + #ifdef UNICODE_ENABLE + process_unicode(keycode, record) && + #endif + true)) { + return false; + } + + // Shift / paren setup + + switch(keycode) { + case RESET: + if (record->event.pressed) { + clear_keyboard(); + #ifdef AUDIO_ENABLE + stop_all_notes(); + shutdown_user(); + #endif + wait_ms(250); + #ifdef ATREUS_ASTAR + *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific + #endif + bootloader_jump(); + return false; + } + break; + case DEBUG: + if (record->event.pressed) { + print("\nDEBUG: enabled.\n"); + debug_enable = true; + return false; + } + break; + case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_UNSWAP_ALT_GUI: + if (record->event.pressed) { + // MAGIC actions (BOOTMAGIC without the boot) + if (!eeconfig_is_enabled()) { + eeconfig_init(); + } + /* keymap config */ + keymap_config.raw = eeconfig_read_keymap(); + if (keycode == MAGIC_SWAP_CONTROL_CAPSLOCK) { + keymap_config.swap_control_capslock = 1; + } else if (keycode == MAGIC_CAPSLOCK_TO_CONTROL) { + keymap_config.capslock_to_control = 1; + } else if (keycode == MAGIC_SWAP_LALT_LGUI) { + keymap_config.swap_lalt_lgui = 1; + } else if (keycode == MAGIC_SWAP_RALT_RGUI) { + keymap_config.swap_ralt_rgui = 1; + } else if (keycode == MAGIC_NO_GUI) { + keymap_config.no_gui = 1; + } else if (keycode == MAGIC_SWAP_GRAVE_ESC) { + keymap_config.swap_grave_esc = 1; + } else if (keycode == MAGIC_SWAP_BACKSLASH_BACKSPACE) { + keymap_config.swap_backslash_backspace = 1; + } else if (keycode == MAGIC_HOST_NKRO) { + keymap_config.nkro = 1; + } else if (keycode == MAGIC_SWAP_ALT_GUI) { + keymap_config.swap_lalt_lgui = 1; + keymap_config.swap_ralt_rgui = 1; + } + /* UNs */ + else if (keycode == MAGIC_UNSWAP_CONTROL_CAPSLOCK) { + keymap_config.swap_control_capslock = 0; + } else if (keycode == MAGIC_UNCAPSLOCK_TO_CONTROL) { + keymap_config.capslock_to_control = 0; + } else if (keycode == MAGIC_UNSWAP_LALT_LGUI) { + keymap_config.swap_lalt_lgui = 0; + } else if (keycode == MAGIC_UNSWAP_RALT_RGUI) { + keymap_config.swap_ralt_rgui = 0; + } else if (keycode == MAGIC_UNNO_GUI) { + keymap_config.no_gui = 0; + } else if (keycode == MAGIC_UNSWAP_GRAVE_ESC) { + keymap_config.swap_grave_esc = 0; + } else if (keycode == MAGIC_UNSWAP_BACKSLASH_BACKSPACE) { + keymap_config.swap_backslash_backspace = 0; + } else if (keycode == MAGIC_UNHOST_NKRO) { + keymap_config.nkro = 0; + } else if (keycode == MAGIC_UNSWAP_ALT_GUI) { + keymap_config.swap_lalt_lgui = 0; + keymap_config.swap_ralt_rgui = 0; + } + eeconfig_update_keymap(keymap_config.raw); + return false; + } + break; + case KC_LSPO: { + if (record->event.pressed) { + shift_interrupted[0] = false; + register_mods(MOD_BIT(KC_LSFT)); + } + else { + if (!shift_interrupted[0]) { + register_code(LSPO_KEY); + unregister_code(LSPO_KEY); + } + unregister_mods(MOD_BIT(KC_LSFT)); + } + return false; + break; + } + + case KC_RSPC: { + if (record->event.pressed) { + shift_interrupted[1] = false; + register_mods(MOD_BIT(KC_RSFT)); + } + else { + if (!shift_interrupted[1]) { + register_code(RSPC_KEY); + unregister_code(RSPC_KEY); + } + unregister_mods(MOD_BIT(KC_RSFT)); + } + return false; + break; + } + default: { + shift_interrupted[0] = true; + shift_interrupted[1] = true; + break; + } + } + + return process_action_kb(record); +} + +const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 0 +}; + +const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = { + 0, 0, 0, 0, 0, 0, 0, 0, + KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, KC_ESC, 0, 0, 0, 0, + KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, + KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, + KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, + KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, + KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, + KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G, + KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O, + KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W, + KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL +}; + +/* for users whose OSes are set to Colemak */ +#if 0 +#include "keymap_colemak.h" + +const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 0 +}; + +const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = { + 0, 0, 0, 0, 0, 0, 0, 0, + KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, KC_ESC, 0, 0, 0, 0, + KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT, + KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH, + KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, + KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH, + KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G, + CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O, + CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W, + CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS, + KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G, + CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O, + CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W, + CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL +}; + +#endif + +void send_string(const char *str) { + while (1) { + uint8_t keycode; + uint8_t ascii_code = pgm_read_byte(str); + if (!ascii_code) break; + keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]); + if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) { + register_code(KC_LSFT); + register_code(keycode); + unregister_code(keycode); + unregister_code(KC_LSFT); + } + else { + register_code(keycode); + unregister_code(keycode); + } + ++str; + } +} + +void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) { + if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) { + layer_on(layer3); + } else { + layer_off(layer3); + } +} + +void tap_random_base64(void) { + #if defined(__AVR_ATmega32U4__) + uint8_t key = (TCNT0 + TCNT1 + TCNT3 + TCNT4) % 64; + #else + uint8_t key = rand() % 64; + #endif + switch (key) { + case 0 ... 25: + register_code(KC_LSFT); + register_code(key + KC_A); + unregister_code(key + KC_A); + unregister_code(KC_LSFT); + break; + case 26 ... 51: + register_code(key - 26 + KC_A); + unregister_code(key - 26 + KC_A); + break; + case 52: + register_code(KC_0); + unregister_code(KC_0); + break; + case 53 ... 61: + register_code(key - 53 + KC_1); + unregister_code(key - 53 + KC_1); + break; + case 62: + register_code(KC_LSFT); + register_code(KC_EQL); + unregister_code(KC_EQL); + unregister_code(KC_LSFT); + break; + case 63: + register_code(KC_SLSH); + unregister_code(KC_SLSH); + break; + } +} + +void matrix_init_quantum() { + #ifdef BACKLIGHT_ENABLE + backlight_init_ports(); + #endif + matrix_init_kb(); +} + +void matrix_scan_quantum() { + #ifdef AUDIO_ENABLE + matrix_scan_music(); + #endif + + #ifdef TAP_DANCE_ENABLE + matrix_scan_tap_dance(); + #endif + matrix_scan_kb(); +} + +#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN) + +static const uint8_t backlight_pin = BACKLIGHT_PIN; + +#if BACKLIGHT_PIN == B7 +# define COM1x1 COM1C1 +# define OCR1x OCR1C +#elif BACKLIGHT_PIN == B6 +# define COM1x1 COM1B1 +# define OCR1x OCR1B +#elif BACKLIGHT_PIN == B5 +# define COM1x1 COM1A1 +# define OCR1x OCR1A +#else +# error "Backlight pin not supported - use B5, B6, or B7" +#endif + +__attribute__ ((weak)) +void backlight_init_ports(void) +{ + + // Setup backlight pin as output and output low. + // DDRx |= n + _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF); + // PORTx &= ~n + _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); + + // Use full 16-bit resolution. + ICR1 = 0xFFFF; + + // I could write a wall of text here to explain... but TL;DW + // Go read the ATmega32u4 datasheet. + // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on + + // Pin PB7 = OCR1C (Timer 1, Channel C) + // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0 + // (i.e. start high, go low when counter matches.) + // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0 + // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1 + + TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010; + TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001; + + backlight_init(); + #ifdef BACKLIGHT_BREATHING + breathing_defaults(); + #endif +} + +__attribute__ ((weak)) +void backlight_set(uint8_t level) +{ + // Prevent backlight blink on lowest level + // PORTx &= ~n + _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF); + + if ( level == 0 ) { + // Turn off PWM control on backlight pin, revert to output low. + TCCR1A &= ~(_BV(COM1x1)); + OCR1x = 0x0; + } else if ( level == BACKLIGHT_LEVELS ) { + // Turn on PWM control of backlight pin + TCCR1A |= _BV(COM1x1); + // Set the brightness + OCR1x = 0xFFFF; + } else { + // Turn on PWM control of backlight pin + TCCR1A |= _BV(COM1x1); + // Set the brightness + OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2)); + } + + #ifdef BACKLIGHT_BREATHING + breathing_intensity_default(); + #endif +} + + +#ifdef BACKLIGHT_BREATHING + +#define BREATHING_NO_HALT 0 +#define BREATHING_HALT_OFF 1 +#define BREATHING_HALT_ON 2 + +static uint8_t breath_intensity; +static uint8_t breath_speed; +static uint16_t breathing_index; +static uint8_t breathing_halt; + +void breathing_enable(void) +{ + if (get_backlight_level() == 0) + { + breathing_index = 0; + } + else + { + // Set breathing_index to be at the midpoint (brightest point) + breathing_index = 0x20 << breath_speed; + } + + breathing_halt = BREATHING_NO_HALT; + + // Enable breathing interrupt + TIMSK1 |= _BV(OCIE1A); +} + +void breathing_pulse(void) +{ + if (get_backlight_level() == 0) + { + breathing_index = 0; + } + else + { + // Set breathing_index to be at the midpoint + 1 (brightest point) + breathing_index = 0x21 << breath_speed; + } + + breathing_halt = BREATHING_HALT_ON; + + // Enable breathing interrupt + TIMSK1 |= _BV(OCIE1A); +} + +void breathing_disable(void) +{ + // Disable breathing interrupt + TIMSK1 &= ~_BV(OCIE1A); + backlight_set(get_backlight_level()); +} + +void breathing_self_disable(void) +{ + if (get_backlight_level() == 0) + { + breathing_halt = BREATHING_HALT_OFF; + } + else + { + breathing_halt = BREATHING_HALT_ON; + } + + //backlight_set(get_backlight_level()); +} + +void breathing_toggle(void) +{ + if (!is_breathing()) + { + if (get_backlight_level() == 0) + { + breathing_index = 0; + } + else + { + // Set breathing_index to be at the midpoint + 1 (brightest point) + breathing_index = 0x21 << breath_speed; + } + + breathing_halt = BREATHING_NO_HALT; + } + + // Toggle breathing interrupt + TIMSK1 ^= _BV(OCIE1A); + + // Restore backlight level + if (!is_breathing()) + { + backlight_set(get_backlight_level()); + } +} + +bool is_breathing(void) +{ + return (TIMSK1 && _BV(OCIE1A)); +} + +void breathing_intensity_default(void) +{ + //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS); + breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2)); +} + +void breathing_intensity_set(uint8_t value) +{ + breath_intensity = value; +} + +void breathing_speed_default(void) +{ + breath_speed = 4; +} + +void breathing_speed_set(uint8_t value) +{ + bool is_breathing_now = is_breathing(); + uint8_t old_breath_speed = breath_speed; + + if (is_breathing_now) + { + // Disable breathing interrupt + TIMSK1 &= ~_BV(OCIE1A); + } + + breath_speed = value; + + if (is_breathing_now) + { + // Adjust index to account for new speed + breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed; + + // Enable breathing interrupt + TIMSK1 |= _BV(OCIE1A); + } + +} + +void breathing_speed_inc(uint8_t value) +{ + if ((uint16_t)(breath_speed - value) > 10 ) + { + breathing_speed_set(0); + } + else + { + breathing_speed_set(breath_speed - value); + } +} + +void breathing_speed_dec(uint8_t value) +{ + if ((uint16_t)(breath_speed + value) > 10 ) + { + breathing_speed_set(10); + } + else + { + breathing_speed_set(breath_speed + value); + } +} + +void breathing_defaults(void) +{ + breathing_intensity_default(); + breathing_speed_default(); + breathing_halt = BREATHING_NO_HALT; +} + +/* Breathing Sleep LED brighness(PWM On period) table + * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle + * + * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 + * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } + */ +static const uint8_t breathing_table[64] PROGMEM = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, + 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, +255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, + 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +ISR(TIMER1_COMPA_vect) +{ + // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity; + + + uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F; + + if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F))) + { + // Disable breathing interrupt + TIMSK1 &= ~_BV(OCIE1A); + } + + OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity; + +} + + + +#endif // breathing + +#else // backlight + +__attribute__ ((weak)) +void backlight_init_ports(void) +{ + +} + +__attribute__ ((weak)) +void backlight_set(uint8_t level) +{ + +} + +#endif // backlight + + + +__attribute__ ((weak)) +void led_set_user(uint8_t usb_led) { + +} + +__attribute__ ((weak)) +void led_set_kb(uint8_t usb_led) { + led_set_user(usb_led); +} + +__attribute__ ((weak)) +void led_init_ports(void) +{ + +} + +__attribute__ ((weak)) +void led_set(uint8_t usb_led) +{ + + // Example LED Code + // + // // Using PE6 Caps Lock LED + // if (usb_led & (1<<USB_LED_CAPS_LOCK)) + // { + // // Output high. + // DDRE |= (1<<6); + // PORTE |= (1<<6); + // } + // else + // { + // // Output low. + // DDRE &= ~(1<<6); + // PORTE &= ~(1<<6); + // } + + led_set_kb(usb_led); +} + + +//------------------------------------------------------------------------------ +// Override these functions in your keymap file to play different tunes on +// different events such as startup and bootloader jump + +__attribute__ ((weak)) +void startup_user() {} + +__attribute__ ((weak)) +void shutdown_user() {} + +//------------------------------------------------------------------------------ diff --git a/quantum/quantum.h b/quantum/quantum.h new file mode 100644 index 0000000000..3a0b742028 --- /dev/null +++ b/quantum/quantum.h @@ -0,0 +1,107 @@ +#ifndef QUANTUM_H +#define QUANTUM_H + +#if defined(__AVR__) +#include <avr/pgmspace.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#endif +#include "wait.h" +#include "matrix.h" +#include "keymap.h" +#ifdef BACKLIGHT_ENABLE + #include "backlight.h" +#endif +#ifdef RGBLIGHT_ENABLE + #include "rgblight.h" +#endif + +#include "action_layer.h" +#include "eeconfig.h" +#include <stddef.h> +#include "bootloader.h" +#include "timer.h" +#include "config_common.h" +#include "led.h" +#include "action_util.h" +#include <stdlib.h> + + +extern uint32_t default_layer_state; + +#ifndef NO_ACTION_LAYER + extern uint32_t layer_state; +#endif + +#ifdef MIDI_ENABLE + #include <lufa.h> + #include "process_midi.h" +#endif + +#ifdef AUDIO_ENABLE + #include "audio.h" + #include "process_music.h" +#endif + +#ifndef DISABLE_LEADER + #include "process_leader.h" +#endif + +#define DISABLE_CHORDING +#ifndef DISABLE_CHORDING + #include "process_chording.h" +#endif + +#ifdef UNICODE_ENABLE + #include "process_unicode.h" +#endif + +#include "process_tap_dance.h" + +#define SEND_STRING(str) send_string(PSTR(str)) +void send_string(const char *str); + +// For tri-layer +void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); + +void tap_random_base64(void); + +#define IS_LAYER_ON(layer) (layer_state & (1UL << (layer))) +#define IS_LAYER_OFF(layer) (~layer_state & (1UL << (layer))) + +void matrix_init_kb(void); +void matrix_scan_kb(void); +void matrix_init_user(void); +void matrix_scan_user(void); +bool process_action_kb(keyrecord_t *record); +bool process_record_kb(uint16_t keycode, keyrecord_t *record); +bool process_record_user(uint16_t keycode, keyrecord_t *record); + +void startup_user(void); +void shutdown_user(void); + +#ifdef BACKLIGHT_ENABLE +void backlight_init_ports(void); + +#ifdef BACKLIGHT_BREATHING +void breathing_enable(void); +void breathing_pulse(void); +void breathing_disable(void); +void breathing_self_disable(void); +void breathing_toggle(void); +bool is_breathing(void); + +void breathing_defaults(void); +void breathing_intensity_default(void); +void breathing_speed_default(void); +void breathing_speed_set(uint8_t value); +void breathing_speed_inc(uint8_t value); +void breathing_speed_dec(uint8_t value); +#endif + +#endif + +void led_set_user(uint8_t usb_led); +void led_set_kb(uint8_t usb_led); + +#endif diff --git a/quantum/rgblight.c b/quantum/rgblight.c new file mode 100644 index 0000000000..c29ffedc38 --- /dev/null +++ b/quantum/rgblight.c @@ -0,0 +1,505 @@ +#include <avr/eeprom.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "progmem.h" +#include "timer.h" +#include "rgblight.h" +#include "debug.h" + +const uint8_t DIM_CURVE[] PROGMEM = { + 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, + 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, + 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, + 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, + 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, + 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, + 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, + 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, + 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, +}; +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}; +const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; +const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; +const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; +const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; +const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; + +rgblight_config_t rgblight_config; +rgblight_config_t inmem_config; +struct cRGB led[RGBLED_NUM]; +uint8_t rgblight_inited = 0; + + +void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) { + /* convert hue, saturation and brightness ( HSB/HSV ) to RGB + The DIM_CURVE is used only on brightness/value and on saturation (inverted). + This looks the most natural. + */ + uint8_t r = 0, g = 0, b = 0; + + val = pgm_read_byte(&DIM_CURVE[val]); + sat = 255 - pgm_read_byte(&DIM_CURVE[255 - sat]); + + uint8_t base; + + if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. + r = val; + g = val; + b = val; + } else { + base = ((255 - sat) * val) >> 8; + + switch (hue / 60) { + case 0: + r = val; + g = (((val - base)*hue) / 60) + base; + b = base; + break; + + case 1: + r = (((val - base)*(60 - (hue % 60))) / 60) + base; + g = val; + b = base; + break; + + case 2: + r = base; + g = val; + b = (((val - base)*(hue % 60)) / 60) + base; + break; + + case 3: + r = base; + g = (((val - base)*(60 - (hue % 60))) / 60) + base; + b = val; + break; + + case 4: + r = (((val - base)*(hue % 60)) / 60) + base; + g = base; + b = val; + break; + + case 5: + r = val; + g = base; + b = (((val - base)*(60 - (hue % 60))) / 60) + base; + break; + } + } + setrgb(r,g,b, led1); +} + +void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { + (*led1).r = r; + (*led1).g = g; + (*led1).b = b; +} + + +uint32_t eeconfig_read_rgblight(void) { + return eeprom_read_dword(EECONFIG_RGBLIGHT); +} +void eeconfig_update_rgblight(uint32_t val) { + eeprom_update_dword(EECONFIG_RGBLIGHT, val); +} +void eeconfig_update_rgblight_default(void) { + dprintf("eeconfig_update_rgblight_default\n"); + rgblight_config.enable = 1; + rgblight_config.mode = 1; + rgblight_config.hue = 200; + rgblight_config.sat = 204; + rgblight_config.val = 204; + eeconfig_update_rgblight(rgblight_config.raw); +} +void eeconfig_debug_rgblight(void) { + dprintf("rgblight_config eprom\n"); + dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); + dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); + dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); + dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); + dprintf("rgblight_config.val = %d\n", rgblight_config.val); +} + +void rgblight_init(void) { + debug_enable = 1; // Debug ON! + dprintf("rgblight_init called.\n"); + rgblight_inited = 1; + dprintf("rgblight_init start!\n"); + if (!eeconfig_is_enabled()) { + dprintf("rgblight_init eeconfig is not enabled.\n"); + eeconfig_init(); + eeconfig_update_rgblight_default(); + } + rgblight_config.raw = eeconfig_read_rgblight(); + if (!rgblight_config.mode) { + dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); + eeconfig_update_rgblight_default(); + rgblight_config.raw = eeconfig_read_rgblight(); + } + eeconfig_debug_rgblight(); // display current eeprom values + + rgblight_timer_init(); // setup the timer + + if (rgblight_config.enable) { + rgblight_mode(rgblight_config.mode); + } +} + +void rgblight_increase(void) { + uint8_t mode = 0; + if (rgblight_config.mode < RGBLIGHT_MODES) { + mode = rgblight_config.mode + 1; + } + rgblight_mode(mode); +} + +void rgblight_decrease(void) { + uint8_t mode = 0; + if (rgblight_config.mode > 1) { //mode will never < 1, if mode is less than 1, eeprom need to be initialized. + mode = rgblight_config.mode-1; + } + rgblight_mode(mode); +} + +void rgblight_step(void) { + uint8_t mode = 0; + mode = rgblight_config.mode + 1; + if (mode > RGBLIGHT_MODES) { + mode = 1; + } + rgblight_mode(mode); +} + +void rgblight_mode(uint8_t mode) { + if (!rgblight_config.enable) { + return; + } + if (mode<1) { + rgblight_config.mode = 1; + } else if (mode > RGBLIGHT_MODES) { + rgblight_config.mode = RGBLIGHT_MODES; + } else { + rgblight_config.mode = mode; + } + eeconfig_update_rgblight(rgblight_config.raw); + xprintf("rgblight mode: %u\n", rgblight_config.mode); + if (rgblight_config.mode == 1) { + rgblight_timer_disable(); + } else if (rgblight_config.mode >=2 && rgblight_config.mode <=23) { + // MODE 2-5, breathing + // MODE 6-8, rainbow mood + // MODE 9-14, rainbow swirl + // MODE 15-20, snake + // MODE 21-23, knight + rgblight_timer_enable(); + } + rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); +} + +void rgblight_toggle(void) { + rgblight_config.enable ^= 1; + eeconfig_update_rgblight(rgblight_config.raw); + xprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable); + if (rgblight_config.enable) { + rgblight_mode(rgblight_config.mode); + } else { + rgblight_timer_disable(); + _delay_ms(50); + rgblight_set(); + } +} + + +void rgblight_increase_hue(void){ + uint16_t hue; + hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360; + rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); +} +void rgblight_decrease_hue(void){ + uint16_t hue; + if (rgblight_config.hue-RGBLIGHT_HUE_STEP <0 ) { + hue = (rgblight_config.hue+360-RGBLIGHT_HUE_STEP) % 360; + } else { + hue = (rgblight_config.hue-RGBLIGHT_HUE_STEP) % 360; + } + rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); +} +void rgblight_increase_sat(void) { + uint8_t sat; + if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) { + sat = 255; + } else { + sat = rgblight_config.sat+RGBLIGHT_SAT_STEP; + } + rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); +} +void rgblight_decrease_sat(void){ + uint8_t sat; + if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) { + sat = 0; + } else { + sat = rgblight_config.sat-RGBLIGHT_SAT_STEP; + } + rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); +} +void rgblight_increase_val(void){ + uint8_t val; + if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) { + val = 255; + } else { + val = rgblight_config.val+RGBLIGHT_VAL_STEP; + } + rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); +} +void rgblight_decrease_val(void) { + uint8_t val; + if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) { + val = 0; + } else { + val = rgblight_config.val-RGBLIGHT_VAL_STEP; + } + rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); +} + +void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val){ + inmem_config.raw = rgblight_config.raw; + if (rgblight_config.enable) { + struct cRGB tmp_led; + sethsv(hue, sat, val, &tmp_led); + inmem_config.hue = hue; + inmem_config.sat = sat; + inmem_config.val = val; + // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val); + rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); + } +} +void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val){ + if (rgblight_config.enable) { + if (rgblight_config.mode == 1) { + // same static color + rgblight_sethsv_noeeprom(hue, sat, val); + } else { + // all LEDs in same color + if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { + // breathing mode, ignore the change of val, use in memory value instead + val = rgblight_config.val; + } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) { + // rainbow mood and rainbow swirl, ignore the change of hue + hue = rgblight_config.hue; + } + } + rgblight_config.hue = hue; + rgblight_config.sat = sat; + rgblight_config.val = val; + eeconfig_update_rgblight(rgblight_config.raw); + xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); + } +} + +void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b){ + // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b); + for (uint8_t i=0;i<RGBLED_NUM;i++) { + led[i].r = r; + led[i].g = g; + led[i].b = b; + } + rgblight_set(); + +} + +void rgblight_set(void) { + if (rgblight_config.enable) { + ws2812_setleds(led, RGBLED_NUM); + } else { + for (uint8_t i=0;i<RGBLED_NUM;i++) { + led[i].r = 0; + led[i].g = 0; + led[i].b = 0; + } + ws2812_setleds(led, RGBLED_NUM); + } +} + +// Animation timer -- AVR Timer3 +void rgblight_timer_init(void) { + static uint8_t rgblight_timer_is_init = 0; + if (rgblight_timer_is_init) { + return; + } + rgblight_timer_is_init = 1; + /* Timer 3 setup */ + TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP + | _BV(CS30); //Clock selelct: clk/1 + /* Set TOP value */ + uint8_t sreg = SREG; + cli(); + OCR3AH = (RGBLED_TIMER_TOP>>8)&0xff; + OCR3AL = RGBLED_TIMER_TOP&0xff; + SREG = sreg; +} +void rgblight_timer_enable(void) { + TIMSK3 |= _BV(OCIE3A); + dprintf("TIMER3 enabled.\n"); +} +void rgblight_timer_disable(void) { + TIMSK3 &= ~_BV(OCIE3A); + dprintf("TIMER3 disabled.\n"); +} +void rgblight_timer_toggle(void) { + TIMSK3 ^= _BV(OCIE3A); + dprintf("TIMER3 toggled.\n"); +} + +ISR(TIMER3_COMPA_vect) { + // Mode = 1, static light, do nothing here + if (rgblight_config.mode>=2 && rgblight_config.mode<=5) { + // mode = 2 to 5, breathing mode + rgblight_effect_breathing(rgblight_config.mode-2); + + } else if (rgblight_config.mode>=6 && rgblight_config.mode<=8) { + rgblight_effect_rainbow_mood(rgblight_config.mode-6); + } else if (rgblight_config.mode>=9 && rgblight_config.mode<=14) { + rgblight_effect_rainbow_swirl(rgblight_config.mode-9); + } else if (rgblight_config.mode>=15 && rgblight_config.mode<=20) { + rgblight_effect_snake(rgblight_config.mode-15); + } else if (rgblight_config.mode>=21 && rgblight_config.mode<=23) { + rgblight_effect_knight(rgblight_config.mode-21); + } +} + +// effects +void rgblight_effect_breathing(uint8_t interval) { + static uint8_t pos = 0; + static uint16_t last_timer = 0; + + if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) return; + last_timer = timer_read(); + + rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos])); + pos = (pos+1) % 256; +} + +void rgblight_effect_rainbow_mood(uint8_t interval) { + static uint16_t current_hue=0; + static uint16_t last_timer = 0; + + if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) return; + last_timer = timer_read(); + rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val); + current_hue = (current_hue+1) % 360; +} + +void rgblight_effect_rainbow_swirl(uint8_t interval) { + static uint16_t current_hue=0; + static uint16_t last_timer = 0; + uint16_t hue; + uint8_t i; + if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval/2])) return; + last_timer = timer_read(); + for (i=0; i<RGBLED_NUM; i++) { + hue = (360/RGBLED_NUM*i+current_hue)%360; + sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]); + } + rgblight_set(); + + if (interval % 2) { + current_hue = (current_hue+1) % 360; + } else { + if (current_hue -1 < 0) { + current_hue = 359; + } else { + current_hue = current_hue - 1; + } + + } +} +void rgblight_effect_snake(uint8_t interval) { + static uint8_t pos=0; + static uint16_t last_timer = 0; + uint8_t i,j; + int8_t k; + int8_t increament = 1; + if (interval%2) increament = -1; + if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval/2])) return; + last_timer = timer_read(); + for (i=0;i<RGBLED_NUM;i++) { + led[i].r=0; + led[i].g=0; + led[i].b=0; + for (j=0;j<RGBLIGHT_EFFECT_SNAKE_LENGTH;j++) { + k = pos+j*increament; + if (k<0) k = k+RGBLED_NUM; + if (i==k) { + sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]); + } + } + } + rgblight_set(); + if (increament == 1) { + if (pos - 1 < 0) { + pos = RGBLED_NUM-1; + } else { + pos -= 1; + } + } else { + pos = (pos+1)%RGBLED_NUM; + } + +} + +void rgblight_effect_knight(uint8_t interval) { + static int8_t pos=0; + static uint16_t last_timer = 0; + uint8_t i,j,cur; + int8_t k; + struct cRGB preled[RGBLED_NUM]; + static int8_t increament = -1; + if (timer_elapsed(last_timer)<pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) return; + last_timer = timer_read(); + for (i=0;i<RGBLED_NUM;i++) { + preled[i].r=0; + preled[i].g=0; + preled[i].b=0; + for (j=0;j<RGBLIGHT_EFFECT_KNIGHT_LENGTH;j++) { + k = pos+j*increament; + if (k<0) k = 0; + if (k>=RGBLED_NUM) k=RGBLED_NUM-1; + if (i==k) { + sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); + } + } + } + if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) { + for (i=0;i<RGBLED_NUM;i++) { + cur = (i+RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM; + led[i].r = preled[cur].r; + led[i].g = preled[cur].g; + led[i].b = preled[cur].b; + } + } + rgblight_set(); + if (increament == 1) { + if (pos - 1 < 0 - RGBLIGHT_EFFECT_KNIGHT_LENGTH) { + pos = 0- RGBLIGHT_EFFECT_KNIGHT_LENGTH; + increament = -1; + } else { + pos -= 1; + } + } else { + if (pos+1>RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH) { + pos = RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH-1; + increament = 1; + } else { + pos += 1; + } + } + +} diff --git a/quantum/rgblight.h b/quantum/rgblight.h new file mode 100644 index 0000000000..64f92523e0 --- /dev/null +++ b/quantum/rgblight.h @@ -0,0 +1,86 @@ +#ifndef RGBLIGHT_H +#define RGBLIGHT_H + +#ifndef RGBLIGHT_MODES +#define RGBLIGHT_MODES 23 +#endif + +#ifndef RGBLIGHT_EFFECT_SNAKE_LENGTH +#define RGBLIGHT_EFFECT_SNAKE_LENGTH 7 +#endif + +#ifndef RGBLIGHT_EFFECT_KNIGHT_LENGTH +#define RGBLIGHT_EFFECT_KNIGHT_LENGTH 7 +#endif +#ifndef RGBLIGHT_EFFECT_KNIGHT_OFFSET +#define RGBLIGHT_EFFECT_KNIGHT_OFFSET 9 +#endif + +#ifndef RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH +#define RGBLIGHT_EFFECT_DUALKNIGHT_LENGTH 4 +#endif + +#ifndef RGBLIGHT_HUE_STEP +#define RGBLIGHT_HUE_STEP 10 +#endif +#ifndef RGBLIGHT_SAT_STEP +#define RGBLIGHT_SAT_STEP 17 +#endif +#ifndef RGBLIGHT_VAL_STEP +#define RGBLIGHT_VAL_STEP 17 +#endif + +#define RGBLED_TIMER_TOP F_CPU/(256*64) + +#include <stdint.h> +#include <stdbool.h> +#include "eeconfig.h" +#include "light_ws2812.h" + +typedef union { + uint32_t raw; + struct { + bool enable :1; + uint8_t mode :6; + uint16_t hue :9; + uint8_t sat :8; + uint8_t val :8; + }; +} rgblight_config_t; + +void rgblight_init(void); +void rgblight_increase(void); +void rgblight_decrease(void); +void rgblight_toggle(void); +void rgblight_step(void); +void rgblight_mode(uint8_t mode); +void rgblight_set(void); +void rgblight_increase_hue(void); +void rgblight_decrease_hue(void); +void rgblight_increase_sat(void); +void rgblight_decrease_sat(void); +void rgblight_increase_val(void); +void rgblight_decrease_val(void); +void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val); +void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b); + +uint32_t eeconfig_read_rgblight(void); +void eeconfig_update_rgblight(uint32_t val); +void eeconfig_update_rgblight_default(void); +void eeconfig_debug_rgblight(void); + +void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); +void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1); +void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val); + +void rgblight_timer_init(void); +void rgblight_timer_enable(void); +void rgblight_timer_disable(void); +void rgblight_timer_toggle(void); +void rgblight_effect_breathing(uint8_t interval); +void rgblight_effect_rainbow_mood(uint8_t interval); +void rgblight_effect_rainbow_swirl(uint8_t interval); +void rgblight_effect_snake(uint8_t interval); +void rgblight_effect_knight(uint8_t interval); + +#endif diff --git a/quantum/serial_link/.gitignore b/quantum/serial_link/.gitignore new file mode 100644 index 0000000000..2d68e206e8 --- /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 0000000000..991cfe96d7 --- /dev/null +++ b/quantum/serial_link/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cgreen/cgreen"] + path = cgreen/cgreen + url = http://github.com/cgreen-devs/cgreen diff --git a/quantum/serial_link/LICENSE b/quantum/serial_link/LICENSE new file mode 100644 index 0000000000..d7cc3198cb --- /dev/null +++ b/quantum/serial_link/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/quantum/serial_link/README.md b/quantum/serial_link/README.md new file mode 100644 index 0000000000..94af9125ce --- /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 0000000000..6b31a3f923 --- /dev/null +++ b/quantum/serial_link/cgreen/Makefile @@ -0,0 +1,38 @@ +# This Makefile ensures that the build is made out of source in a subdirectory called 'build' +# If it doesn't exist, it is created and a Makefile created there (from Makefile.build) +# +# This Makefile also contains delegation of the most common make commands +# +# If you have cmake installed you should be able to do: +# +# make +# make test +# make install +# make package +# +# That should build cgreen for C and C++, run some tests, install it locally and +# generate two distributable packages. + +all: build + cd $(CGREEN_BUILD_DIR); make all + +test: build + cd $(CGREEN_BUILD_DIR); make test + +clean: build + cd $(CGREEN_BUILD_DIR); make clean + +package: build + cd $(CGREEN_BUILD_DIR); make package + +install: + cd $(CGREEN_BUILD_DIR); make install + +############# Internal + +build: + mkdir -p $(CGREEN_BUILD_DIR) + cp Makefile.build $(CGREEN_BUILD_DIR)/Makefile + + +.SILENT: diff --git a/quantum/serial_link/cgreen/Makefile.build b/quantum/serial_link/cgreen/Makefile.build new file mode 100644 index 0000000000..f76165244c --- /dev/null +++ b/quantum/serial_link/cgreen/Makefile.build @@ -0,0 +1,33 @@ +# This Makefile is copied from the cgreen top directory (where it is +# named Makefile.build) and put in a subdirectory called 'build' where +# builds are made This Makefile then automatically creates +# subdirectories for C and C++ builds configuring them using the cmake +# command. Once created you can always tweak the cmake setup as with +# any cmake build directory + +all: build-c build-c++ + for d in build-* ; do cd $$d; make ; cd .. ; done + +clean: + for d in build-* ; do cd $$d; make clean ; cd .. ; done + +check test: + for d in build-* ; do cd $$d; make check ; cd .. ; done + +package: + for d in build-* ; do cd $$d; make package ; cd .. ; done + +install: + for d in build-* ; do cd $$d; make install ; cd .. ; done + +############ Internal + +build-c: + mkdir build-c + cd build-c; cmake -G "Unix Makefiles" $(CGREEN_DIR) + +build-c++: + mkdir build-c++ + cd build-c++; cmake -G "Unix Makefiles" -DWITH_CXX:bool=ON $(CGREEN_DIR) + +.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 0000000000..e164cc5ff3 --- /dev/null +++ b/quantum/serial_link/serial_link.mk @@ -0,0 +1,27 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016 Fred Sundvik +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +UINCDIR += $(SERIAL_DIR) +SRC += $(wildcard $(SERIAL_DIR)/serial_link/protocol/*.c) +SRC += $(wildcard $(SERIAL_DIR)/serial_link/system/*.c) +SRC += serial_link_hal.c +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 0000000000..fb4c45a8dc --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/byte_stuffer.c @@ -0,0 +1,145 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "serial_link/protocol/byte_stuffer.h" +#include "serial_link/protocol/frame_validator.h" +#include "serial_link/protocol/physical.h" +#include <stdbool.h> + +// This implements the "Consistent overhead byte stuffing protocol" +// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing +// http://www.stuartcheshire.org/papers/COBSforToN.pdf + +#define MAX_FRAME_SIZE 1024 +#define NUM_LINKS 2 + +typedef struct byte_stuffer_state { + uint16_t next_zero; + uint16_t data_pos; + bool long_frame; + uint8_t data[MAX_FRAME_SIZE]; +}byte_stuffer_state_t; + +static byte_stuffer_state_t states[NUM_LINKS]; + +void init_byte_stuffer_state(byte_stuffer_state_t* state) { + state->next_zero = 0; + state->data_pos = 0; + state->long_frame = false; +} + +void init_byte_stuffer(void) { + int i; + for (i=0;i<NUM_LINKS;i++) { + init_byte_stuffer_state(&states[i]); + } +} + +void byte_stuffer_recv_byte(uint8_t link, uint8_t data) { + byte_stuffer_state_t* state = &states[link]; + // Start of a new frame + if (state->next_zero == 0) { + state->next_zero = data; + state->long_frame = data == 0xFF; + state->data_pos = 0; + return; + } + + state->next_zero--; + if (data == 0) { + if (state->next_zero == 0) { + // The frame is completed + if (state->data_pos > 0) { + validator_recv_frame(link, state->data, state->data_pos); + } + } + else { + // The frame is invalid, so reset + init_byte_stuffer_state(state); + } + } + else { + if (state->data_pos == MAX_FRAME_SIZE) { + // We exceeded our maximum frame size + // therefore there's nothing else to do than reset to a new frame + state->next_zero = data; + state->long_frame = data == 0xFF; + state->data_pos = 0; + } + else if (state->next_zero == 0) { + if (state->long_frame) { + // This is part of a long frame, so continue + state->next_zero = data; + state->long_frame = data == 0xFF; + } + else { + // Special case for zeroes + state->next_zero = data; + state->data[state->data_pos++] = 0; + } + } + else { + state->data[state->data_pos++] = data; + } + } +} + +static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) { + send_data(link, &num_non_zero, 1); + if (end > start) { + send_data(link, start, end-start); + } +} + +void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { + const uint8_t zero = 0; + if (size > 0) { + uint16_t num_non_zero = 1; + uint8_t* end = data + size; + uint8_t* start = data; + while (data < end) { + if (num_non_zero == 0xFF) { + // There's more data after big non-zero block + // So send it, and start a new block + send_block(link, start, data, num_non_zero); + start = data; + num_non_zero = 1; + } + else { + if (*data == 0) { + // A zero encountered, so send the block + send_block(link, start, data, num_non_zero); + start = data + 1; + num_non_zero = 1; + } + else { + num_non_zero++; + } + ++data; + } + } + send_block(link, start, data, num_non_zero); + send_data(link, &zero, 1); + } +} 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 0000000000..2cc88beb42 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/byte_stuffer.h @@ -0,0 +1,34 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_BYTE_STUFFER_H +#define SERIAL_LINK_BYTE_STUFFER_H + +#include <stdint.h> + +void init_byte_stuffer(void); +void byte_stuffer_recv_byte(uint8_t link, uint8_t data); +void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size); + +#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 0000000000..04b8c2e75c --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/frame_router.c @@ -0,0 +1,69 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "serial_link/protocol/frame_router.h" +#include "serial_link/protocol/transport.h" +#include "serial_link/protocol/frame_validator.h" + +static bool is_master; + +void router_set_master(bool master) { + is_master = master; +} + +void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size){ + if (is_master) { + if (link == DOWN_LINK) { + transport_recv_frame(data[size-1], data, size - 1); + } + } + else { + if (link == UP_LINK) { + if (data[size-1] & 1) { + transport_recv_frame(0, data, size - 1); + } + data[size-1] >>= 1; + validator_send_frame(DOWN_LINK, data, size); + } + else { + data[size-1]++; + validator_send_frame(UP_LINK, data, size); + } + } +} + +void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { + if (destination == 0) { + if (!is_master) { + data[size] = 1; + validator_send_frame(UP_LINK, data, size + 1); + } + } + else { + if (is_master) { + data[size] = destination; + validator_send_frame(DOWN_LINK, data, size + 1); + } + } +} 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 0000000000..712250ff35 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/frame_router.h @@ -0,0 +1,38 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_FRAME_ROUTER_H +#define SERIAL_LINK_FRAME_ROUTER_H + +#include <stdint.h> +#include <stdbool.h> + +#define UP_LINK 0 +#define DOWN_LINK 1 + +void router_set_master(bool master); +void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size); +void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size); + +#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 0000000000..474f80ee8e --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/frame_validator.c @@ -0,0 +1,121 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "serial_link/protocol/frame_validator.h" +#include "serial_link/protocol/frame_router.h" +#include "serial_link/protocol/byte_stuffer.h" +#include <string.h> + +const uint32_t poly8_lookup[256] = +{ + 0, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +static uint32_t crc32_byte(uint8_t *p, uint32_t bytelength) +{ + uint32_t crc = 0xffffffff; + while (bytelength-- !=0) crc = poly8_lookup[((uint8_t) crc ^ *(p++))] ^ (crc >> 8); + // return (~crc); also works + return (crc ^ 0xffffffff); +} + +void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { + if (size > 4) { + uint32_t frame_crc; + memcpy(&frame_crc, data + size -4, 4); + uint32_t expected_crc = crc32_byte(data, size - 4); + if (frame_crc == expected_crc) { + route_incoming_frame(link, data, size-4); + } + } +} + +void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size) { + uint32_t crc = crc32_byte(data, size); + memcpy(data + size, &crc, 4); + byte_stuffer_send_frame(link, data, size + 4); +} 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 0000000000..4a910d510b --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/frame_validator.h @@ -0,0 +1,34 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_FRAME_VALIDATOR_H +#define SERIAL_LINK_FRAME_VALIDATOR_H + +#include <stdint.h> + +void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size); +// The buffer pointed to by the data needs 4 additional bytes +void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size); + +#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 0000000000..425e06cdd2 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/physical.h @@ -0,0 +1,30 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_PHYSICAL_H +#define SERIAL_LINK_PHYSICAL_H + +void send_data(uint8_t link, const uint8_t* data, uint16_t size); + +#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 0000000000..f418d11ceb --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/transport.c @@ -0,0 +1,124 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "serial_link/protocol/transport.h" +#include "serial_link/protocol/frame_router.h" +#include "serial_link/protocol/triple_buffered_object.h" +#include <string.h> + +#define MAX_REMOTE_OBJECTS 16 +static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS]; +static uint32_t num_remote_objects = 0; + +void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) { + unsigned int i; + for(i=0;i<_num_remote_objects;i++) { + remote_object_t* obj = _remote_objects[i]; + remote_objects[num_remote_objects++] = obj; + if (obj->object_type == MASTER_TO_ALL_SLAVES) { + triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; + triple_buffer_init(tb); + uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); + tb = (triple_buffer_object_t*)start; + triple_buffer_init(tb); + } + else if(obj->object_type == MASTER_TO_SINGLE_SLAVE) { + uint8_t* start = obj->buffer; + unsigned int j; + for (j=0;j<NUM_SLAVES;j++) { + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; + triple_buffer_init(tb); + start += LOCAL_OBJECT_SIZE(obj->object_size); + } + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; + triple_buffer_init(tb); + } + else { + uint8_t* start = obj->buffer; + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; + triple_buffer_init(tb); + start += LOCAL_OBJECT_SIZE(obj->object_size); + unsigned int j; + for (j=0;j<NUM_SLAVES;j++) { + tb = (triple_buffer_object_t*)start; + triple_buffer_init(tb); + start += REMOTE_OBJECT_SIZE(obj->object_size); + } + } + } +} + +void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { + uint8_t id = data[size-1]; + if (id < num_remote_objects) { + remote_object_t* obj = remote_objects[id]; + if (obj->object_size == size - 1) { + uint8_t* start; + if (obj->object_type == MASTER_TO_ALL_SLAVES) { + start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); + } + else if(obj->object_type == SLAVE_TO_MASTER) { + start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); + start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size); + } + else { + start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size); + } + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; + void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb); + memcpy(ptr, data, size - 1); + triple_buffer_end_write_internal(tb); + } + } +} + +void update_transport(void) { + unsigned int i; + for(i=0;i<num_remote_objects;i++) { + remote_object_t* obj = remote_objects[i]; + if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) { + triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; + uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); + if (ptr) { + ptr[obj->object_size] = i; + uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0; + router_send_frame(dest, ptr, obj->object_size + 1); + } + } + else { + uint8_t* start = obj->buffer; + unsigned int j; + for (j=0;j<NUM_SLAVES;j++) { + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; + uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); + if (ptr) { + ptr[obj->object_size] = i; + uint8_t dest = j + 1; + router_send_frame(dest, ptr, obj->object_size + 1); + } + start += LOCAL_OBJECT_SIZE(obj->object_size); + } + } + } +} 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 0000000000..9a052d8809 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/transport.h @@ -0,0 +1,151 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_TRANSPORT_H +#define SERIAL_LINK_TRANSPORT_H + +#include "serial_link/protocol/triple_buffered_object.h" +#include "serial_link/system/serial_link.h" + +#define NUM_SLAVES 8 +#define LOCAL_OBJECT_EXTRA 16 + +// master -> slave = 1 local(target all), 1 remote object +// slave -> master = 1 local(target 0), multiple remote objects +// master -> single slave (multiple local, target id), 1 remote object +typedef enum { + MASTER_TO_ALL_SLAVES, + MASTER_TO_SINGLE_SLAVE, + SLAVE_TO_MASTER, +} remote_object_type; + +typedef struct { + remote_object_type object_type; + uint16_t object_size; + uint8_t buffer[] __attribute__((aligned(4))); +} remote_object_t; + +#define REMOTE_OBJECT_SIZE(objectsize) \ + (sizeof(triple_buffer_object_t) + objectsize * 3) +#define LOCAL_OBJECT_SIZE(objectsize) \ + (sizeof(triple_buffer_object_t) + (objectsize + LOCAL_OBJECT_EXTRA) * 3) + +#define REMOTE_OBJECT_HELPER(name, type, num_local, num_remote) \ +typedef struct { \ + remote_object_t object; \ + uint8_t buffer[ \ + num_remote * REMOTE_OBJECT_SIZE(sizeof(type)) + \ + num_local * LOCAL_OBJECT_SIZE(sizeof(type))]; \ +} remote_object_##name##_t; + +#define MASTER_TO_ALL_SLAVES_OBJECT(name, type) \ + REMOTE_OBJECT_HELPER(name, type, 1, 1) \ + remote_object_##name##_t remote_object_##name = { \ + .object = { \ + .object_type = MASTER_TO_ALL_SLAVES, \ + .object_size = sizeof(type), \ + } \ + }; \ + type* begin_write_##name(void) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ + return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ + }\ + void end_write_##name(void) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ + triple_buffer_end_write_internal(tb); \ + signal_data_written(); \ + }\ + type* read_##name(void) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ + return triple_buffer_read_internal(obj->object_size, tb); \ + } + +#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \ + REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \ + remote_object_##name##_t remote_object_##name = { \ + .object = { \ + .object_type = MASTER_TO_SINGLE_SLAVE, \ + .object_size = sizeof(type), \ + } \ + }; \ + type* begin_write_##name(uint8_t slave) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + uint8_t* start = obj->buffer;\ + start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ + return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ + }\ + void end_write_##name(uint8_t slave) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + uint8_t* start = obj->buffer;\ + start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ + triple_buffer_end_write_internal(tb); \ + signal_data_written(); \ + }\ + type* read_##name() { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\ + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ + return triple_buffer_read_internal(obj->object_size, tb); \ + } + +#define SLAVE_TO_MASTER_OBJECT(name, type) \ + REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \ + remote_object_##name##_t remote_object_##name = { \ + .object = { \ + .object_type = SLAVE_TO_MASTER, \ + .object_size = sizeof(type), \ + } \ + }; \ + type* begin_write_##name(void) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ + return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ + }\ + void end_write_##name(void) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ + triple_buffer_end_write_internal(tb); \ + signal_data_written(); \ + }\ + type* read_##name(uint8_t slave) { \ + remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ + uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ + start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \ + triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ + return triple_buffer_read_internal(obj->object_size, tb); \ + } + +#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name + +void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); +void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); +void update_transport(void); + +#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 0000000000..e3e8989d30 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/triple_buffered_object.c @@ -0,0 +1,78 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "serial_link/protocol/triple_buffered_object.h" +#include "serial_link/system/serial_link.h" +#include <stdbool.h> +#include <stddef.h> + +#define GET_READ_INDEX() object->state & 3 +#define GET_WRITE_INDEX() (object->state >> 2) & 3 +#define GET_SHARED_INDEX() (object->state >> 4) & 3 +#define GET_DATA_AVAILABLE() (object->state >> 6) & 1 + +#define SET_READ_INDEX(i) object->state = ((object->state & ~3) | i) +#define SET_WRITE_INDEX(i) object->state = ((object->state & ~(3 << 2)) | (i << 2)) +#define SET_SHARED_INDEX(i) object->state = ((object->state & ~(3 << 4)) | (i << 4)) +#define SET_DATA_AVAILABLE(i) object->state = ((object->state & ~(1 << 6)) | (i << 6)) + +void triple_buffer_init(triple_buffer_object_t* object) { + object->state = 0; + SET_WRITE_INDEX(0); + SET_READ_INDEX(1); + SET_SHARED_INDEX(2); + SET_DATA_AVAILABLE(0); +} + +void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object) { + serial_link_lock(); + if (GET_DATA_AVAILABLE()) { + uint8_t shared_index = GET_SHARED_INDEX(); + uint8_t read_index = GET_READ_INDEX(); + SET_READ_INDEX(shared_index); + SET_SHARED_INDEX(read_index); + SET_DATA_AVAILABLE(false); + serial_link_unlock(); + return object->buffer + object_size * shared_index; + } + else { + serial_link_unlock(); + return NULL; + } +} + +void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object) { + uint8_t write_index = GET_WRITE_INDEX(); + return object->buffer + object_size * write_index; +} + +void triple_buffer_end_write_internal(triple_buffer_object_t* object) { + serial_link_lock(); + uint8_t shared_index = GET_SHARED_INDEX(); + uint8_t write_index = GET_WRITE_INDEX(); + SET_SHARED_INDEX(write_index); + SET_WRITE_INDEX(shared_index); + SET_DATA_AVAILABLE(true); + serial_link_unlock(); +} 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 0000000000..2e57db3f50 --- /dev/null +++ b/quantum/serial_link/serial_link/protocol/triple_buffered_object.h @@ -0,0 +1,51 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H +#define SERIAL_LINK_TRIPLE_BUFFERED_OBJECT_H + +#include <stdint.h> + +typedef struct { + uint8_t state; + uint8_t buffer[] __attribute__((aligned(4))); +}triple_buffer_object_t; + +void triple_buffer_init(triple_buffer_object_t* object); + +#define triple_buffer_begin_write(object) \ + (typeof(*object.buffer[0])*)triple_buffer_begin_write_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object) + +#define triple_buffer_end_write(object) \ + triple_buffer_end_write_internal((triple_buffer_object_t*)object) + +#define triple_buffer_read(object) \ + (typeof(*object.buffer[0])*)triple_buffer_read_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object) + +void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object); +void triple_buffer_end_write_internal(triple_buffer_object_t* object); +void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object); + + +#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 0000000000..75c7e77a76 --- /dev/null +++ b/quantum/serial_link/serial_link/system/serial_link.c @@ -0,0 +1,265 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#include "report.h" +#include "host_driver.h" +#include "serial_link/system/serial_link.h" +#include "hal.h" +#include "serial_link/protocol/byte_stuffer.h" +#include "serial_link/protocol/transport.h" +#include "serial_link/protocol/frame_router.h" +#include "matrix.h" +#include <stdbool.h> +#include "print.h" +#include "config.h" + +static event_source_t new_data_event; +static bool serial_link_connected; +static bool is_master = false; + +static uint8_t keyboard_leds(void); +static void send_keyboard(report_keyboard_t *report); +static void send_mouse(report_mouse_t *report); +static void send_system(uint16_t data); +static void send_consumer(uint16_t data); + +host_driver_t serial_driver = { + keyboard_leds, + send_keyboard, + send_mouse, + send_system, + send_consumer +}; + +// Define these in your Config.h file +#ifndef SERIAL_LINK_BAUD +#error "Serial link baud is not set" +#endif + +#ifndef SERIAL_LINK_THREAD_PRIORITY +#error "Serial link thread priority not set" +#endif + +static SerialConfig config = { + .sc_speed = SERIAL_LINK_BAUD +}; + +//#define DEBUG_LINK_ERRORS + +static uint32_t read_from_serial(SerialDriver* driver, uint8_t link) { + const uint32_t buffer_size = 16; + uint8_t buffer[buffer_size]; + uint32_t bytes_read = sdAsynchronousRead(driver, buffer, buffer_size); + uint8_t* current = buffer; + uint8_t* end = current + bytes_read; + while(current < end) { + byte_stuffer_recv_byte(link, *current); + current++; + } + return bytes_read; +} + +static void print_error(char* str, eventflags_t flags, SerialDriver* driver) { +#ifdef DEBUG_LINK_ERRORS + if (flags & SD_PARITY_ERROR) { + print(str); + print(" Parity error\n"); + } + if (flags & SD_FRAMING_ERROR) { + print(str); + print(" Framing error\n"); + } + if (flags & SD_OVERRUN_ERROR) { + print(str); + uint32_t size = qSpaceI(&(driver->iqueue)); + xprintf(" Overrun error, queue size %d\n", size); + + } + if (flags & SD_NOISE_ERROR) { + print(str); + print(" Noise error\n"); + } + if (flags & SD_BREAK_DETECTED) { + print(str); + print(" Break detected\n"); + } +#else + (void)str; + (void)flags; + (void)driver; +#endif +} + +bool is_serial_link_master(void) { + return is_master; +} + +// TODO: Optimize the stack size, this is probably way too big +static THD_WORKING_AREA(serialThreadStack, 1024); +static THD_FUNCTION(serialThread, arg) { + (void)arg; + event_listener_t new_data_listener; + event_listener_t sd1_listener; + event_listener_t sd2_listener; + chEvtRegister(&new_data_event, &new_data_listener, 0); + eventflags_t events = CHN_INPUT_AVAILABLE + | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED; + chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1), + &sd1_listener, + EVENT_MASK(1), + events); + chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2), + &sd2_listener, + EVENT_MASK(2), + events); + bool need_wait = false; + while(true) { + eventflags_t flags1 = 0; + eventflags_t flags2 = 0; + if (need_wait) { + eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(1000)); + if (mask & EVENT_MASK(1)) { + flags1 = chEvtGetAndClearFlags(&sd1_listener); + print_error("DOWNLINK", flags1, &SD1); + } + if (mask & EVENT_MASK(2)) { + flags2 = chEvtGetAndClearFlags(&sd2_listener); + print_error("UPLINK", flags2, &SD2); + } + } + + // Always stay as master, even if the USB goes into sleep mode + is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE; + router_set_master(is_master); + + need_wait = true; + need_wait &= read_from_serial(&SD2, UP_LINK) == 0; + need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0; + update_transport(); + } +} + +void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + if (link == DOWN_LINK) { + sdWrite(&SD1, data, size); + } + else { + sdWrite(&SD2, data, size); + } +} + +static systime_t last_update = 0; + +typedef struct { + matrix_row_t rows[MATRIX_ROWS]; +} matrix_object_t; + +static matrix_object_t last_matrix = {}; + +SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t); +MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool); + +static remote_object_t* remote_objects[] = { + REMOTE_OBJECT(serial_link_connected), + REMOTE_OBJECT(keyboard_matrix), +}; + +void init_serial_link(void) { + serial_link_connected = false; + init_serial_link_hal(); + add_remote_objects(remote_objects, sizeof(remote_objects)/sizeof(remote_object_t*)); + init_byte_stuffer(); + sdStart(&SD1, &config); + sdStart(&SD2, &config); + chEvtObjectInit(&new_data_event); + (void)chThdCreateStatic(serialThreadStack, sizeof(serialThreadStack), + SERIAL_LINK_THREAD_PRIORITY, serialThread, NULL); +} + +void matrix_set_remote(matrix_row_t* rows, uint8_t index); + +void serial_link_update(void) { + if (read_serial_link_connected()) { + serial_link_connected = true; + } + + matrix_object_t matrix; + bool changed = false; + for(uint8_t i=0;i<MATRIX_ROWS;i++) { + matrix.rows[i] = matrix_get_row(i); + changed |= matrix.rows[i] != last_matrix.rows[i]; + } + + systime_t current_time = chVTGetSystemTimeX(); + systime_t delta = current_time - last_update; + if (changed || delta > US2ST(1000)) { + last_update = current_time; + last_matrix = matrix; + matrix_object_t* m = begin_write_keyboard_matrix(); + for(uint8_t i=0;i<MATRIX_ROWS;i++) { + m->rows[i] = matrix.rows[i]; + } + end_write_keyboard_matrix(); + *begin_write_serial_link_connected() = true; + end_write_serial_link_connected(); + } + + matrix_object_t* m = read_keyboard_matrix(0); + if (m) { + matrix_set_remote(m->rows, 0); + } +} + +void signal_data_written(void) { + chEvtBroadcast(&new_data_event); +} + +bool is_serial_link_connected(void) { + return serial_link_connected; +} + +host_driver_t* get_serial_link_driver(void) { + return &serial_driver; +} + +// NOTE: The driver does nothing, because the master handles everything +uint8_t keyboard_leds(void) { + return 0; +} + +void send_keyboard(report_keyboard_t *report) { + (void)report; +} + +void send_mouse(report_mouse_t *report) { + (void)report; +} + +void send_system(uint16_t data) { + (void)data; +} + +void send_consumer(uint16_t data) { + (void)data; +} + 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 0000000000..351e03877b --- /dev/null +++ b/quantum/serial_link/serial_link/system/serial_link.h @@ -0,0 +1,63 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef SERIAL_LINK_H +#define SERIAL_LINK_H + +#include "host_driver.h" +#include <stdbool.h> + +void init_serial_link(void); +void init_serial_link_hal(void); +bool is_serial_link_connected(void); +bool is_serial_link_master(void); +host_driver_t* get_serial_link_driver(void); +void serial_link_update(void); + +#if defined(PROTOCOL_CHIBIOS) +#include "ch.h" + +static inline void serial_link_lock(void) { + chSysLock(); +} + +static inline void serial_link_unlock(void) { + chSysUnlock(); +} + +void signal_data_written(void); + +#else + +inline void serial_link_lock(void) { +} + +inline void serial_link_unlock(void) { +} + +void signal_data_written(void); + +#endif + +#endif diff --git a/quantum/serial_link/serial_link/tests/Makefile b/quantum/serial_link/serial_link/tests/Makefile new file mode 100644 index 0000000000..1b072c6f1d --- /dev/null +++ b/quantum/serial_link/serial_link/tests/Makefile @@ -0,0 +1,61 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016 Fred Sundvik +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +CC = gcc +CFLAGS = +INCLUDES = -I. -I../../ +LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared +LDLIBS = -lcgreen +UNITOBJ = $(BUILDDIR)/serialtest/unitobj +DEPDIR = $(BUILDDIR)/serialtest/unit.d +UNITTESTS = $(BUILDDIR)/serialtest/unittests +DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td +EXT = .so +UNAME := $(shell uname) +ifneq (, $(findstring MINGW, $(UNAME))) + EXT = .dll +endif +ifneq (, $(findstring CYGWIN, $(UNAME))) + EXT = .dll +endif + +SRC = $(wildcard *.c) +TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC)) +$(shell mkdir -p $(DEPDIR) >/dev/null) + +test: $(TESTFILES) + @$(BUILDDIR)/cgreen/build-c/tools/cgreen-runner --color $(TESTFILES) + +$(UNITTESTS)/%$(EXT): $(UNITOBJ)/%.o + @mkdir -p $(UNITTESTS) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +$(UNITOBJ)/%.o : %.c +$(UNITOBJ)/%.o: %.c $(DEPDIR)/%.d + @mkdir -p $(UNITOBJ) + $(CC) $(CFLAGS) $(DEPFLAGS) $(INCLUDES) -c $< -o $@ + @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d + +$(DEPDIR)/%.d: ; +.PRECIOUS: $(DEPDIR)/%.d + +-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 0000000000..64b170e8c1 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/byte_stuffer_tests.c @@ -0,0 +1,506 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include <cgreen/cgreen.h> +#include <cgreen/mocks.h> +#include "serial_link/protocol/byte_stuffer.h" +#include "serial_link/protocol/byte_stuffer.c" +#include "serial_link/protocol/frame_validator.h" +#include "serial_link/protocol/physical.h" + +static uint8_t sent_data[MAX_FRAME_SIZE*2]; +static uint16_t sent_data_size; + +Describe(ByteStuffer); +BeforeEach(ByteStuffer) { + init_byte_stuffer(); + sent_data_size = 0; +} +AfterEach(ByteStuffer) {} + +void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { + mock(data, size); +} + +void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + memcpy(sent_data + sent_data_size, data, size); + sent_data_size += size; +} + +Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { + never_expect(validator_recv_frame); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { + never_expect(validator_recv_frame); + byte_stuffer_recv_byte(0, 0xFF); +} + +Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) { + never_expect(validator_recv_frame); + byte_stuffer_recv_byte(0, 0x4A); +} + +Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) { + never_expect(validator_recv_frame); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_single_byte_valid_frame) { + uint8_t expected[] = {0x37}; + expect(validator_recv_frame, + when(size, is_equal_to(1)), + when(data, is_equal_to_contents_of(expected, 1)) + ); + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 0x37); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_three_bytes_valid_frame) { + uint8_t expected[] = {0x37, 0x99, 0xFF}; + expect(validator_recv_frame, + when(size, is_equal_to(3)), + when(data, is_equal_to_contents_of(expected, 3)) + ); + byte_stuffer_recv_byte(0, 4); + byte_stuffer_recv_byte(0, 0x37); + byte_stuffer_recv_byte(0, 0x99); + byte_stuffer_recv_byte(0, 0xFF); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_single_zero_valid_frame) { + uint8_t expected[] = {0}; + expect(validator_recv_frame, + when(size, is_equal_to(1)), + when(data, is_equal_to_contents_of(expected, 1)) + ); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_valid_frame_with_zeroes) { + uint8_t expected[] = {5, 0, 3, 0}; + expect(validator_recv_frame, + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(expected, 4)) + ); + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 5); + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 3); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_two_valid_frames) { + uint8_t expected1[] = {5, 0}; + uint8_t expected2[] = {3}; + expect(validator_recv_frame, + when(size, is_equal_to(2)), + when(data, is_equal_to_contents_of(expected1, 2)) + ); + expect(validator_recv_frame, + when(size, is_equal_to(1)), + when(data, is_equal_to_contents_of(expected2, 1)) + ); + byte_stuffer_recv_byte(1, 2); + byte_stuffer_recv_byte(1, 5); + byte_stuffer_recv_byte(1, 1); + byte_stuffer_recv_byte(1, 0); + byte_stuffer_recv_byte(1, 2); + byte_stuffer_recv_byte(1, 3); + byte_stuffer_recv_byte(1, 0); +} + +Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) { + uint8_t expected[] = {5, 7}; + expect(validator_recv_frame, + when(size, is_equal_to(2)), + when(data, is_equal_to_contents_of(expected, 2)) + ); + byte_stuffer_recv_byte(1, 3); + byte_stuffer_recv_byte(1, 1); + byte_stuffer_recv_byte(1, 0); + byte_stuffer_recv_byte(1, 3); + byte_stuffer_recv_byte(1, 5); + byte_stuffer_recv_byte(1, 7); + byte_stuffer_recv_byte(1, 0); +} + +Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { + uint8_t expected[] = {5, 7}; + expect(validator_recv_frame, + when(size, is_equal_to(2)), + when(data, is_equal_to_contents_of(expected, 2)) + ); + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 9); + byte_stuffer_recv_byte(0, 4); // This should have been zero + byte_stuffer_recv_byte(0, 0); + byte_stuffer_recv_byte(0, 3); + byte_stuffer_recv_byte(0, 5); + byte_stuffer_recv_byte(0, 7); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) { + uint8_t expected[254]; + int i; + for (i=0;i<254;i++) { + expected[i] = i + 1; + } + expect(validator_recv_frame, + when(size, is_equal_to(254)), + when(data, is_equal_to_contents_of(expected, 254)) + ); + byte_stuffer_recv_byte(0, 0xFF); + for (i=0;i<254;i++) { + byte_stuffer_recv_byte(0, i+1); + } + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) { + uint8_t expected[255]; + int i; + for (i=0;i<254;i++) { + expected[i] = i + 1; + } + expected[254] = 7; + expect(validator_recv_frame, + when(size, is_equal_to(255)), + when(data, is_equal_to_contents_of(expected, 255)) + ); + byte_stuffer_recv_byte(0, 0xFF); + for (i=0;i<254;i++) { + byte_stuffer_recv_byte(0, i+1); + } + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 7); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) { + uint8_t expected[255]; + int i; + for (i=0;i<254;i++) { + expected[i] = i + 1; + } + expected[254] = 0; + expect(validator_recv_frame, + when(size, is_equal_to(255)), + when(data, is_equal_to_contents_of(expected, 255)) + ); + byte_stuffer_recv_byte(0, 0xFF); + for (i=0;i<254;i++) { + byte_stuffer_recv_byte(0, i+1); + } + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_two_long_frames_and_some_more) { + uint8_t expected[515]; + int i; + int j; + for (j=0;j<2;j++) { + for (i=0;i<254;i++) { + expected[i+254*j] = i + 1; + } + } + for (i=0;i<7;i++) { + expected[254*2+i] = i + 1; + } + expect(validator_recv_frame, + when(size, is_equal_to(515)), + when(data, is_equal_to_contents_of(expected, 510)) + ); + byte_stuffer_recv_byte(0, 0xFF); + for (i=0;i<254;i++) { + byte_stuffer_recv_byte(0, i+1); + } + byte_stuffer_recv_byte(0, 0xFF); + for (i=0;i<254;i++) { + byte_stuffer_recv_byte(0, i+1); + } + byte_stuffer_recv_byte(0, 8); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 3); + byte_stuffer_recv_byte(0, 4); + byte_stuffer_recv_byte(0, 5); + byte_stuffer_recv_byte(0, 6); + byte_stuffer_recv_byte(0, 7); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { + uint8_t expected[MAX_FRAME_SIZE] = {}; + expect(validator_recv_frame, + when(size, is_equal_to(MAX_FRAME_SIZE)), + when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE)) + ); + int i; + byte_stuffer_recv_byte(0, 1); + for(i=0;i<MAX_FRAME_SIZE;i++) { + byte_stuffer_recv_byte(0, 1); + } + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { + uint8_t expected[1] = {0}; + never_expect(validator_recv_frame); + int i; + byte_stuffer_recv_byte(0, 1); + for(i=0;i<MAX_FRAME_SIZE;i++) { + byte_stuffer_recv_byte(0, 1); + } + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) { + uint8_t expected[1] = {1}; + expect(validator_recv_frame, + when(size, is_equal_to(1)), + when(data, is_equal_to_contents_of(expected, 1)) + ); + int i; + byte_stuffer_recv_byte(0, 1); + for(i=0;i<MAX_FRAME_SIZE;i++) { + byte_stuffer_recv_byte(0, 1); + } + byte_stuffer_recv_byte(0, 2); + byte_stuffer_recv_byte(0, 1); + byte_stuffer_recv_byte(0, 0); +} + +Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) { + assert_that(sent_data_size, is_equal_to(0)); + byte_stuffer_send_frame(0, NULL, 0); +} + +Ensure(ByteStuffer, send_one_byte_frame) { + uint8_t data[] = {5}; + byte_stuffer_send_frame(1, data, 1); + uint8_t expected[] = {2, 5, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_two_byte_frame) { + uint8_t data[] = {5, 0x77}; + byte_stuffer_send_frame(0, data, 2); + uint8_t expected[] = {3, 5, 0x77, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_one_byte_frame_with_zero) { + uint8_t data[] = {0}; + byte_stuffer_send_frame(0, data, 1); + uint8_t expected[] = {1, 1, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) { + uint8_t data[] = {0, 9}; + byte_stuffer_send_frame(1, data, 2); + uint8_t expected[] = {1, 2, 9, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) { + uint8_t data[] = {9, 0}; + byte_stuffer_send_frame(1, data, 2); + uint8_t expected[] = {2, 9, 1, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) { + uint8_t data[] = {9, 0, 0x68}; + byte_stuffer_send_frame(0, data, 3); + uint8_t expected[] = {2, 9, 2, 0x68, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) { + uint8_t data[] = {0, 0x55, 0}; + byte_stuffer_send_frame(0, data, 3); + uint8_t expected[] = {1, 2, 0x55, 1, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) { + uint8_t data[] = {0, 0, 0}; + byte_stuffer_send_frame(0, data, 3); + uint8_t expected[] = {1, 1, 1, 1, 0}; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) { + uint8_t data[254]; + int i; + for(i=0;i<254;i++) { + data[i] = i + 1; + } + byte_stuffer_send_frame(0, data, 254); + uint8_t expected[256]; + expected[0] = 0xFF; + for(i=1;i<255;i++) { + expected[i] = i; + } + expected[255] = 0; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) { + uint8_t data[255]; + int i; + for(i=0;i<255;i++) { + data[i] = i + 1; + } + byte_stuffer_send_frame(0, data, 255); + uint8_t expected[258]; + expected[0] = 0xFF; + for(i=1;i<255;i++) { + expected[i] = i; + } + expected[255] = 2; + expected[256] = 255; + expected[257] = 0; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { + uint8_t data[255]; + int i; + for(i=0;i<254;i++) { + data[i] = i + 1; + } + data[255] = 0; + byte_stuffer_send_frame(0, data, 255); + uint8_t expected[258]; + expected[0] = 0xFF; + for(i=1;i<255;i++) { + expected[i] = i; + } + expected[255] = 1; + expected[256] = 1; + expected[257] = 0; + assert_that(sent_data_size, is_equal_to(sizeof(expected))); + assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); +} + +Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) { + uint8_t original_data[] = { 1, 2, 3}; + byte_stuffer_send_frame(0, original_data, sizeof(original_data)); + expect(validator_recv_frame, + when(size, is_equal_to(sizeof(original_data))), + when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) + ); + int i; + for(i=0;i<sent_data_size;i++) { + byte_stuffer_recv_byte(1, sent_data[i]); + } +} + +Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) { + uint8_t original_data[] = { 1, 0, 3, 0, 0, 9}; + byte_stuffer_send_frame(1, original_data, sizeof(original_data)); + expect(validator_recv_frame, + when(size, is_equal_to(sizeof(original_data))), + when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) + ); + int i; + for(i=0;i<sent_data_size;i++) { + byte_stuffer_recv_byte(0, sent_data[i]); + } +} + +Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) { + uint8_t original_data[254]; + int i; + for(i=0;i<254;i++) { + original_data[i] = i + 1; + } + byte_stuffer_send_frame(0, original_data, sizeof(original_data)); + expect(validator_recv_frame, + when(size, is_equal_to(sizeof(original_data))), + when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) + ); + for(i=0;i<sent_data_size;i++) { + byte_stuffer_recv_byte(1, sent_data[i]); + } +} + +Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { + uint8_t original_data[256]; + int i; + for(i=0;i<254;i++) { + original_data[i] = i + 1; + } + original_data[254] = 22; + original_data[255] = 23; + byte_stuffer_send_frame(0, original_data, sizeof(original_data)); + expect(validator_recv_frame, + when(size, is_equal_to(sizeof(original_data))), + when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) + ); + for(i=0;i<sent_data_size;i++) { + byte_stuffer_recv_byte(1, sent_data[i]); + } +} + +Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { + uint8_t original_data[255]; + int i; + for(i=0;i<254;i++) { + original_data[i] = i + 1; + } + original_data[254] = 0; + byte_stuffer_send_frame(0, original_data, sizeof(original_data)); + expect(validator_recv_frame, + when(size, is_equal_to(sizeof(original_data))), + when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) + ); + for(i=0;i<sent_data_size;i++) { + byte_stuffer_recv_byte(1, sent_data[i]); + } +} 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 0000000000..6c806fa939 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/frame_router_tests.c @@ -0,0 +1,231 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include <cgreen/cgreen.h> +#include <cgreen/mocks.h> +#include "serial_link/protocol/byte_stuffer.c" +#include "serial_link/protocol/frame_validator.c" +#include "serial_link/protocol/frame_router.c" +#include "serial_link/protocol/transport.h" + +static uint8_t received_data[256]; +static uint16_t received_data_size; + +typedef struct { + uint8_t sent_data[256]; + uint16_t sent_data_size; +} receive_buffer_t; + +typedef struct { + receive_buffer_t send_buffers[2]; +} router_buffer_t; + +router_buffer_t router_buffers[8]; + +router_buffer_t* current_router_buffer; + + +Describe(FrameRouter); +BeforeEach(FrameRouter) { + init_byte_stuffer(); + memset(router_buffers, 0, sizeof(router_buffers)); + current_router_buffer = 0; +} +AfterEach(FrameRouter) {} + +typedef struct { + uint32_t data; + uint8_t extra[16]; +} frame_buffer_t; + + +void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + receive_buffer_t* buffer = ¤t_router_buffer->send_buffers[link]; + memcpy(buffer->sent_data + buffer->sent_data_size, data, size); + buffer->sent_data_size += size; +} + +static void receive_data(uint8_t link, uint8_t* data, uint16_t size) { + int i; + for(i=0;i<size;i++) { + byte_stuffer_recv_byte(link, data[i]); + } +} + +static void activate_router(uint8_t num) { + current_router_buffer = router_buffers + num; + router_set_master(num==0); +} + +static void simulate_transport(uint8_t from, uint8_t to) { + activate_router(to); + if (from > to) { + receive_data(DOWN_LINK, + router_buffers[from].send_buffers[UP_LINK].sent_data, + router_buffers[from].send_buffers[UP_LINK].sent_data_size); + } + else if(to > from) { + receive_data(UP_LINK, + router_buffers[from].send_buffers[DOWN_LINK].sent_data, + router_buffers[from].send_buffers[DOWN_LINK].sent_data_size); + } +} + +void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { + mock(from, data, size); +} + + +Ensure(FrameRouter, master_broadcast_is_received_by_everyone) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(0); + router_send_frame(0xFF, (uint8_t*)&data, 4); + assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + + expect(transport_recv_frame, + when(from, is_equal_to(0)), + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(&data.data, 4)) + ); + simulate_transport(0, 1); + assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + + expect(transport_recv_frame, + when(from, is_equal_to(0)), + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(&data.data, 4)) + ); + simulate_transport(1, 2); + assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); +} + +Ensure(FrameRouter, master_send_is_received_by_targets) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(0); + router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4); + assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + + simulate_transport(0, 1); + assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + + expect(transport_recv_frame, + when(from, is_equal_to(0)), + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(&data.data, 4)) + ); + simulate_transport(1, 2); + assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + + expect(transport_recv_frame, + when(from, is_equal_to(0)), + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(&data.data, 4)) + ); + simulate_transport(2, 3); + assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); +} + +Ensure(FrameRouter, first_link_sends_to_master) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(1); + router_send_frame(0, (uint8_t*)&data, 4); + assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); + + expect(transport_recv_frame, + when(from, is_equal_to(1)), + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(&data.data, 4)) + ); + simulate_transport(1, 0); + assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); + assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); +} + +Ensure(FrameRouter, second_link_sends_to_master) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(2); + router_send_frame(0, (uint8_t*)&data, 4); + assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); + + simulate_transport(2, 1); + assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); + + expect(transport_recv_frame, + when(from, is_equal_to(2)), + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(&data.data, 4)) + ); + simulate_transport(1, 0); + assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); + assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); +} + +Ensure(FrameRouter, master_sends_to_master_does_nothing) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(0); + router_send_frame(0, (uint8_t*)&data, 4); + assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); +} + +Ensure(FrameRouter, link_sends_to_other_link_does_nothing) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(1); + router_send_frame(2, (uint8_t*)&data, 4); + assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); +} + +Ensure(FrameRouter, master_receives_on_uplink_does_nothing) { + frame_buffer_t data; + data.data = 0xAB7055BB; + activate_router(1); + router_send_frame(0, (uint8_t*)&data, 4); + assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); + assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); + + never_expect(transport_recv_frame); + activate_router(0); + receive_data(UP_LINK, + router_buffers[1].send_buffers[UP_LINK].sent_data, + router_buffers[1].send_buffers[UP_LINK].sent_data_size); + assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); + assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); +} 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 0000000000..d20947e2c9 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/frame_validator_tests.c @@ -0,0 +1,101 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include <cgreen/cgreen.h> +#include <cgreen/mocks.h> +#include "serial_link/protocol/frame_validator.c" + +void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { + mock(data, size); +} + +void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { + mock(data, size); +} + +Describe(FrameValidator); +BeforeEach(FrameValidator) {} +AfterEach(FrameValidator) {} + +Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) { + never_expect(route_incoming_frame); + uint8_t data[] = {1, 2}; + validator_recv_frame(0, 0, 1); + validator_recv_frame(0, data, 2); + validator_recv_frame(0, data, 3); + validator_recv_frame(0, data, 4); +} + +Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) { + uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; + expect(route_incoming_frame, + when(size, is_equal_to(1)), + when(data, is_equal_to_contents_of(data, 1)) + ); + validator_recv_frame(0, data, 5); +} + +Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) { + uint8_t data[] = {0x44, 0, 0, 0, 0}; + never_expect(route_incoming_frame); + validator_recv_frame(1, data, 5); +} + +Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) { + uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA}; + expect(route_incoming_frame, + when(size, is_equal_to(4)), + when(data, is_equal_to_contents_of(data, 4)) + ); + validator_recv_frame(1, data, 8); +} + +Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) { + uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; + expect(route_incoming_frame, + when(size, is_equal_to(5)), + when(data, is_equal_to_contents_of(data, 5)) + ); + validator_recv_frame(0, data, 9); +} + +Ensure(FrameValidator, sends_one_byte_with_correct_crc) { + uint8_t original[] = {0x44, 0, 0, 0, 0}; + uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; + expect(byte_stuffer_send_frame, + when(size, is_equal_to(sizeof(expected))), + when(data, is_equal_to_contents_of(expected, sizeof(expected))) + ); + validator_send_frame(0, original, 1); +} + +Ensure(FrameValidator, sends_five_bytes_with_correct_crc) { + uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0}; + uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; + expect(byte_stuffer_send_frame, + when(size, is_equal_to(sizeof(expected))), + when(data, is_equal_to_contents_of(expected, sizeof(expected))) + ); + validator_send_frame(0, original, 5); +} 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 0000000000..358e1b9fd4 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/transport_tests.c @@ -0,0 +1,168 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include <cgreen/cgreen.h> +#include <cgreen/mocks.h> +#include "serial_link/protocol/transport.c" +#include "serial_link/protocol/triple_buffered_object.c" + +void signal_data_written(void) { + mock(); +} + +static uint8_t sent_data[2048]; +static uint16_t sent_data_size; + +void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { + mock(destination); + memcpy(sent_data + sent_data_size, data, size); + sent_data_size += size; +} + +typedef struct { + uint32_t test; +} test_object1_t; + +typedef struct { + uint32_t test1; + uint32_t test2; +} test_object2_t; + +MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t); +MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t); +SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t); + +static remote_object_t* test_remote_objects[] = { + REMOTE_OBJECT(master_to_slave), + REMOTE_OBJECT(master_to_single_slave), + REMOTE_OBJECT(slave_to_master), +}; + +Describe(Transport); +BeforeEach(Transport) { + add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); + sent_data_size = 0; +} +AfterEach(Transport) {} + +Ensure(Transport, write_to_local_signals_an_event) { + begin_write_master_to_slave(); + expect(signal_data_written); + end_write_master_to_slave(); + begin_write_slave_to_master(); + expect(signal_data_written); + end_write_slave_to_master(); + begin_write_master_to_single_slave(1); + expect(signal_data_written); + end_write_master_to_single_slave(1); +} + +Ensure(Transport, writes_from_master_to_all_slaves) { + update_transport(); + test_object1_t* obj = begin_write_master_to_slave(); + obj->test = 5; + expect(signal_data_written); + end_write_master_to_slave(); + expect(router_send_frame, + when(destination, is_equal_to(0xFF))); + update_transport(); + transport_recv_frame(0, sent_data, sent_data_size); + test_object1_t* obj2 = read_master_to_slave(); + assert_that(obj2, is_not_equal_to(NULL)); + assert_that(obj2->test, is_equal_to(5)); +} + +Ensure(Transport, writes_from_slave_to_master) { + update_transport(); + test_object1_t* obj = begin_write_slave_to_master(); + obj->test = 7; + expect(signal_data_written); + end_write_slave_to_master(); + expect(router_send_frame, + when(destination, is_equal_to(0))); + update_transport(); + transport_recv_frame(3, sent_data, sent_data_size); + test_object1_t* obj2 = read_slave_to_master(2); + assert_that(read_slave_to_master(0), is_equal_to(NULL)); + assert_that(obj2, is_not_equal_to(NULL)); + assert_that(obj2->test, is_equal_to(7)); +} + +Ensure(Transport, writes_from_master_to_single_slave) { + update_transport(); + test_object1_t* obj = begin_write_master_to_single_slave(3); + obj->test = 7; + expect(signal_data_written); + end_write_master_to_single_slave(3); + expect(router_send_frame, + when(destination, is_equal_to(4))); + update_transport(); + transport_recv_frame(0, sent_data, sent_data_size); + test_object1_t* obj2 = read_master_to_single_slave(); + assert_that(obj2, is_not_equal_to(NULL)); + assert_that(obj2->test, is_equal_to(7)); +} + +Ensure(Transport, ignores_object_with_invalid_id) { + update_transport(); + test_object1_t* obj = begin_write_master_to_single_slave(3); + obj->test = 7; + expect(signal_data_written); + end_write_master_to_single_slave(3); + expect(router_send_frame, + when(destination, is_equal_to(4))); + update_transport(); + sent_data[sent_data_size - 1] = 44; + transport_recv_frame(0, sent_data, sent_data_size); + test_object1_t* obj2 = read_master_to_single_slave(); + assert_that(obj2, is_equal_to(NULL)); +} + +Ensure(Transport, ignores_object_with_size_too_small) { + update_transport(); + test_object1_t* obj = begin_write_master_to_slave(); + obj->test = 7; + expect(signal_data_written); + end_write_master_to_slave(); + expect(router_send_frame); + update_transport(); + sent_data[sent_data_size - 2] = 0; + transport_recv_frame(0, sent_data, sent_data_size - 1); + test_object1_t* obj2 = read_master_to_slave(); + assert_that(obj2, is_equal_to(NULL)); +} + +Ensure(Transport, ignores_object_with_size_too_big) { + update_transport(); + test_object1_t* obj = begin_write_master_to_slave(); + obj->test = 7; + expect(signal_data_written); + end_write_master_to_slave(); + expect(router_send_frame); + update_transport(); + sent_data[sent_data_size + 21] = 0; + transport_recv_frame(0, sent_data, sent_data_size + 22); + test_object1_t* obj2 = read_master_to_slave(); + assert_that(obj2, is_equal_to(NULL)); +} 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 0000000000..6f7c82b468 --- /dev/null +++ b/quantum/serial_link/serial_link/tests/triple_buffered_object_tests.c @@ -0,0 +1,82 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include <cgreen/cgreen.h> +#include "serial_link/protocol/triple_buffered_object.c" + +typedef struct { + uint8_t state; + uint32_t buffer[3]; +}test_object_t; + +test_object_t test_object; + +Describe(TripleBufferedObject); +BeforeEach(TripleBufferedObject) { + triple_buffer_init((triple_buffer_object_t*)&test_object); +} +AfterEach(TripleBufferedObject) {} + + +Ensure(TripleBufferedObject, writes_and_reads_object) { + *triple_buffer_begin_write(&test_object) = 0x3456ABCC; + triple_buffer_end_write(&test_object); + assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC)); +} + +Ensure(TripleBufferedObject, does_not_read_empty) { + assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); +} + +Ensure(TripleBufferedObject, writes_twice_and_reads_object) { + *triple_buffer_begin_write(&test_object) = 0x3456ABCC; + triple_buffer_end_write(&test_object); + *triple_buffer_begin_write(&test_object) = 0x44778899; + triple_buffer_end_write(&test_object); + assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899)); +} + +Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) { + *triple_buffer_begin_write(&test_object) = 1; + triple_buffer_end_write(&test_object); + uint32_t* read = triple_buffer_read(&test_object); + *triple_buffer_begin_write(&test_object) = 2; + triple_buffer_end_write(&test_object); + assert_that(*read, is_equal_to(1)); + assert_that(*triple_buffer_read(&test_object), is_equal_to(2)); + assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); +} + +Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { + *triple_buffer_begin_write(&test_object) = 1; + triple_buffer_end_write(&test_object); + uint32_t* read = triple_buffer_read(&test_object); + *triple_buffer_begin_write(&test_object) = 2; + triple_buffer_end_write(&test_object); + *triple_buffer_begin_write(&test_object) = 3; + triple_buffer_end_write(&test_object); + assert_that(*read, is_equal_to(1)); + assert_that(*triple_buffer_read(&test_object), is_equal_to(3)); + assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); +} diff --git a/quantum/serial_link/serial_link_tests.mk b/quantum/serial_link/serial_link_tests.mk new file mode 100644 index 0000000000..e292f582a9 --- /dev/null +++ b/quantum/serial_link/serial_link_tests.mk @@ -0,0 +1,34 @@ +# The MIT License (MIT) +# +# Copyright (c) 2016 Fred Sundvik +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +CGREEN_LIB = $(BUILDDIR)/cgreen/build-c/src/libcgreen.a + +CGREEN_DIR = "$(CURDIR)/$(SERIAL_DIR)/cgreen/cgreen" +CGREEN_BUILD_DIR = "$(CURDIR)/$(BUILDDIR)/cgreen" +export CGREEN_DIR +export CGREEN_BUILD_DIR +$(CGREEN_LIB): + @make -C $(SERIAL_DIR)/cgreen + +.PHONY serialtest: +serialtest : $(CGREEN_LIB) + @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 0000000000..3f6d133c9b --- /dev/null +++ b/quantum/template/Makefile @@ -0,0 +1,75 @@ + + +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=512 + + +# Build Options +# change yes to no to disable +# +BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) +EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) +CONSOLE_ENABLE ?= yes # Console for debug(+400) +COMMAND_ENABLE ?= yes # Commands for debug and configuration +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend +# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +NKRO_ENABLE ?= no # USB Nkey Rollover +BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default +MIDI_ENABLE ?= no # MIDI controls +UNICODE_ENABLE ?= no # Unicode +BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID +AUDIO_ENABLE ?= no # Audio output on port C6 + +ifndef QUANTUM_DIR + include ../../Makefile +endif + + diff --git a/quantum/template/config.h b/quantum/template/config.h new file mode 100644 index 0000000000..b02f0c7ebc --- /dev/null +++ b/quantum/template/config.h @@ -0,0 +1,162 @@ +/* +Copyright 2012 Jun Wako <wakojun@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "config_common.h" + +/* USB Device descriptor parameter */ +#define VENDOR_ID 0xFEED +#define PRODUCT_ID 0x6060 +#define DEVICE_VER 0x0001 +#define MANUFACTURER You +#define PRODUCT %KEYBOARD% +#define DESCRIPTION A custom keyboard + +/* key matrix size */ +#define MATRIX_ROWS 2 +#define MATRIX_COLS 3 + +/* + * Keyboard Matrix Assignments + * + * Change this to how you wired your keyboard + * COLS: AVR pins used for columns, left to right + * ROWS: AVR pins used for rows, top to bottom + * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode) + * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) + * +*/ +#define MATRIX_ROW_PINS { D0, D5 } +#define MATRIX_COL_PINS { F1, F0, B0 } +#define UNUSED_PINS + +/* COL2ROW or ROW2COL */ +#define DIODE_DIRECTION COL2ROW + +// #define BACKLIGHT_PIN B7 +// #define BACKLIGHT_BREATHING +// #define BACKLIGHT_LEVELS 3 + + +/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ +#define DEBOUNCING_DELAY 5 + +/* define if matrix has ghost (lacks anti-ghosting diodes) */ +//#define MATRIX_HAS_GHOST + +/* number of backlight levels */ + +/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ +#define LOCKING_SUPPORT_ENABLE +/* Locking resynchronize hack */ +#define LOCKING_RESYNC_ENABLE + +/* + * Force NKRO + * + * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved + * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the + * makefile for this to work.) + * + * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N) + * until the next keyboard reset. + * + * NKRO may prevent your keystrokes from being detected in the BIOS, but it is + * fully operational during normal computer usage. + * + * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N) + * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by + * bootmagic, NKRO mode will always be enabled until it is toggled again during a + * power-up. + * + */ +//#define FORCE_NKRO + +/* + * Magic Key Options + * + * Magic keys are hotkey commands that allow control over firmware functions of + * the keyboard. They are best used in combination with the HID Listen program, + * found here: https://www.pjrc.com/teensy/hid_listen.html + * + * The options below allow the magic key functionality to be changed. This is + * useful if your keyboard/keypad is missing keys and you want magic key support. + * + */ + +/* key combination for magic key command */ +#define IS_COMMAND() ( \ + keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ +) + +/* control how magic key switches layers */ +//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true +//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true +//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false + +/* override magic key keymap */ +//#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS +//#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS +//#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM +//#define MAGIC_KEY_HELP1 H +//#define MAGIC_KEY_HELP2 SLASH +//#define MAGIC_KEY_DEBUG D +//#define MAGIC_KEY_DEBUG_MATRIX X +//#define MAGIC_KEY_DEBUG_KBD K +//#define MAGIC_KEY_DEBUG_MOUSE M +//#define MAGIC_KEY_VERSION V +//#define MAGIC_KEY_STATUS S +//#define MAGIC_KEY_CONSOLE C +//#define MAGIC_KEY_LAYER0_ALT1 ESC +//#define MAGIC_KEY_LAYER0_ALT2 GRAVE +//#define MAGIC_KEY_LAYER0 0 +//#define MAGIC_KEY_LAYER1 1 +//#define MAGIC_KEY_LAYER2 2 +//#define MAGIC_KEY_LAYER3 3 +//#define MAGIC_KEY_LAYER4 4 +//#define MAGIC_KEY_LAYER5 5 +//#define MAGIC_KEY_LAYER6 6 +//#define MAGIC_KEY_LAYER7 7 +//#define MAGIC_KEY_LAYER8 8 +//#define MAGIC_KEY_LAYER9 9 +//#define MAGIC_KEY_BOOTLOADER PAUSE +//#define MAGIC_KEY_LOCK CAPS +//#define MAGIC_KEY_EEPROM E +//#define MAGIC_KEY_NKRO N +//#define MAGIC_KEY_SLEEP_LED Z + +/* + * Feature disable options + * These options are also useful to firmware size reduction. + */ + +/* disable debug print */ +//#define NO_DEBUG + +/* disable print */ +//#define NO_PRINT + +/* disable action features */ +//#define NO_ACTION_LAYER +//#define NO_ACTION_TAPPING +//#define NO_ACTION_ONESHOT +//#define NO_ACTION_MACRO +//#define NO_ACTION_FUNCTION + +#endif diff --git a/quantum/template/keymaps/default/Makefile b/quantum/template/keymaps/default/Makefile new file mode 100644 index 0000000000..f4671a9d11 --- /dev/null +++ b/quantum/template/keymaps/default/Makefile @@ -0,0 +1,21 @@ +# Build Options +# change to "no" to disable the options, or define them in the Makefile in +# the appropriate keymap folder that will get included automatically +# +BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = no # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality +MIDI_ENABLE = no # MIDI controls +AUDIO_ENABLE = no # Audio output on port C6 +UNICODE_ENABLE = no # Unicode +BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID +RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend + +ifndef QUANTUM_DIR + include ../../../../Makefile +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 0000000000..df06a26206 --- /dev/null +++ b/quantum/template/keymaps/default/config.h @@ -0,0 +1,8 @@ +#ifndef CONFIG_USER_H +#define CONFIG_USER_H + +#include "../../config.h" + +// place overrides here + +#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 0000000000..e28a4723e9 --- /dev/null +++ b/quantum/template/keymaps/default/keymap.c @@ -0,0 +1,44 @@ +#include "%KEYBOARD%.h" + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { +[0] = KEYMAP( /* Base */ + KC_A, KC_1, KC_H, \ + KC_TAB, KC_SPC \ +), +}; + +const uint16_t PROGMEM fn_actions[] = { + +}; + +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + // MACRODOWN only works in this function + switch(id) { + case 0: + if (record->event.pressed) { + register_code(KC_RSFT); + } else { + unregister_code(KC_RSFT); + } + break; + } + return MACRO_NONE; +}; + + +void matrix_init_user(void) { + +} + +void matrix_scan_user(void) { + +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + return true; +} + +void led_set_user(uint8_t usb_led) { + +}
\ 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 0000000000..21aa663d55 --- /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 0000000000..b2fb4dd98d --- /dev/null +++ b/quantum/template/readme.md @@ -0,0 +1,28 @@ +%KEYBOARD% keyboard firmware +====================== + +## Quantum MK Firmware + +For the full Quantum feature list, see [the parent readme.md](/doc/readme.md). + +## Building + +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. + +Depending on which keymap you would like to use, you will have to compile slightly differently. + +### Default + +To build with the default keymap, simply run `make`. + +### Other Keymaps + +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. + +To build the firmware binary hex file with a keymap just do `make` with `keymap` option like: + +``` +$ make keymap=[default|jack|<name>] +``` + +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 0000000000..dcc4b0a221 --- /dev/null +++ b/quantum/template/template.c @@ -0,0 +1,28 @@ +#include "%KEYBOARD%.h" + +void matrix_init_kb(void) { + // put your keyboard start-up code here + // runs once when the firmware starts up + + matrix_init_user(); +} + +void matrix_scan_kb(void) { + // put your looping keyboard code here + // runs every cycle (a lot) + + matrix_scan_user(); +} + +bool process_record_kb(uint16_t keycode, keyrecord_t *record) { + // put your per-action keyboard code here + // runs for every action, just before processing by the firmware + + return process_action_user(record); +} + +void led_set_kb(uint8_t usb_led) { + // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here + + led_set_user(usb_led); +} diff --git a/quantum/template/template.h b/quantum/template/template.h new file mode 100644 index 0000000000..cd78a54e3e --- /dev/null +++ b/quantum/template/template.h @@ -0,0 +1,19 @@ +#ifndef %KEYBOARD_UPPERCASE%_H +#define %KEYBOARD_UPPERCASE%_H + +#include "quantum.h" + +// This a shortcut to help you visually see your layout. +// The following is an example using the Planck MIT layout +// The first section contains all of the arguements +// The second converts the arguments into a two-dimensional array +#define KEYMAP( \ + k00, k01, k02, \ + k10, k11 \ +) \ +{ \ + { k00, k01, k02 }, \ + { k10, KC_NO, k11 }, \ +} + +#endif diff --git a/quantum/tools/eeprom_reset.hex b/quantum/tools/eeprom_reset.hex new file mode 100644 index 0000000000..a8a75389fe --- /dev/null +++ b/quantum/tools/eeprom_reset.hex @@ -0,0 +1,9 @@ +:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:00000001FF diff --git a/quantum/tools/readme.md b/quantum/tools/readme.md new file mode 100644 index 0000000000..5f355256de --- /dev/null +++ b/quantum/tools/readme.md @@ -0,0 +1,6 @@ +`eeprom_reset.hex` is to reset the eeprom on the Atmega32u4, like this: + + dfu-programmer atmega32u4 erase + dfu-programmer atmega32u4 flash --eeprom eeprom_reset.hex + + You'll need to reflash afterwards, because DFU requires the flash to be erased before messing with the eeprom. |