diff options
Diffstat (limited to 'quantum')
82 files changed, 723 insertions, 6320 deletions
diff --git a/quantum/action.c b/quantum/action.c index be135f18f..95f39d23d 100644 --- a/quantum/action.c +++ b/quantum/action.c | |||
| @@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 18 | #include "keycode.h" | 18 | #include "keycode.h" |
| 19 | #include "keyboard.h" | 19 | #include "keyboard.h" |
| 20 | #include "mousekey.h" | 20 | #include "mousekey.h" |
| 21 | #include "programmable_button.h" | ||
| 21 | #include "command.h" | 22 | #include "command.h" |
| 22 | #include "led.h" | 23 | #include "led.h" |
| 23 | #include "action_layer.h" | 24 | #include "action_layer.h" |
| @@ -988,6 +989,10 @@ void clear_keyboard_but_mods_and_keys() { | |||
| 988 | mousekey_clear(); | 989 | mousekey_clear(); |
| 989 | mousekey_send(); | 990 | mousekey_send(); |
| 990 | #endif | 991 | #endif |
| 992 | #ifdef PROGRAMMABLE_BUTTON_ENABLE | ||
| 993 | programmable_button_clear(); | ||
| 994 | programmable_button_send(); | ||
| 995 | #endif | ||
| 991 | } | 996 | } |
| 992 | 997 | ||
| 993 | /** \brief Utilities for actions. (FIXME: Needs better description) | 998 | /** \brief Utilities for actions. (FIXME: Needs better description) |
diff --git a/quantum/api.c b/quantum/api.c deleted file mode 100644 index 168574458..000000000 --- a/quantum/api.c +++ /dev/null | |||
| @@ -1,182 +0,0 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "api.h" | ||
| 18 | #include "quantum.h" | ||
| 19 | |||
| 20 | void dword_to_bytes(uint32_t dword, uint8_t* bytes) { | ||
| 21 | bytes[0] = (dword >> 24) & 0xFF; | ||
| 22 | bytes[1] = (dword >> 16) & 0xFF; | ||
| 23 | bytes[2] = (dword >> 8) & 0xFF; | ||
| 24 | bytes[3] = (dword >> 0) & 0xFF; | ||
| 25 | } | ||
| 26 | |||
| 27 | uint32_t bytes_to_dword(uint8_t* bytes, uint8_t index) { return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3]; } | ||
| 28 | |||
| 29 | __attribute__((weak)) bool process_api_quantum(uint8_t length, uint8_t* data) { return process_api_keyboard(length, data); } | ||
| 30 | |||
| 31 | __attribute__((weak)) bool process_api_keyboard(uint8_t length, uint8_t* data) { return process_api_user(length, data); } | ||
| 32 | |||
| 33 | __attribute__((weak)) bool process_api_user(uint8_t length, uint8_t* data) { return true; } | ||
| 34 | |||
| 35 | void process_api(uint16_t length, uint8_t* data) { | ||
| 36 | // SEND_STRING("\nRX: "); | ||
| 37 | // for (uint8_t i = 0; i < length; i++) { | ||
| 38 | // send_byte(data[i]); | ||
| 39 | // SEND_STRING(" "); | ||
| 40 | // } | ||
| 41 | if (!process_api_quantum(length, data)) return; | ||
| 42 | |||
| 43 | switch (data[0]) { | ||
| 44 | case MT_SET_DATA: | ||
| 45 | switch (data[1]) { | ||
| 46 | case DT_DEFAULT_LAYER: { | ||
| 47 | eeconfig_update_default_layer(data[2]); | ||
| 48 | default_layer_set((uint32_t)(data[2])); | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | case DT_KEYMAP_OPTIONS: { | ||
| 52 | eeconfig_update_keymap(data[2]); | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | case DT_RGBLIGHT: { | ||
| 56 | #ifdef RGBLIGHT_ENABLE | ||
| 57 | uint32_t rgblight = bytes_to_dword(data, 2); | ||
| 58 | eeconfig_update_rgblight(rgblight); | ||
| 59 | #endif | ||
| 60 | break; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | case MT_GET_DATA: | ||
| 64 | switch (data[1]) { | ||
| 65 | case DT_HANDSHAKE: { | ||
| 66 | MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0); | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | case DT_DEBUG: { | ||
| 70 | uint8_t debug_bytes[1] = {eeprom_read_byte(EECONFIG_DEBUG)}; | ||
| 71 | MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1); | ||
| 72 | break; | ||
| 73 | } | ||
| 74 | case DT_DEFAULT_LAYER: { | ||
| 75 | uint8_t default_bytes[1] = {eeprom_read_byte(EECONFIG_DEFAULT_LAYER)}; | ||
| 76 | MT_GET_DATA_ACK(DT_DEFAULT_LAYER, default_bytes, 1); | ||
| 77 | break; | ||
| 78 | } | ||
| 79 | case DT_CURRENT_LAYER: { | ||
| 80 | uint8_t layer_state_bytes[4]; | ||
| 81 | dword_to_bytes(layer_state, layer_state_bytes); | ||
| 82 | MT_GET_DATA_ACK(DT_CURRENT_LAYER, layer_state_bytes, 4); | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | case DT_AUDIO: { | ||
| 86 | #ifdef AUDIO_ENABLE | ||
| 87 | uint8_t audio_bytes[1] = {eeprom_read_byte(EECONFIG_AUDIO)}; | ||
| 88 | MT_GET_DATA_ACK(DT_AUDIO, audio_bytes, 1); | ||
| 89 | #else | ||
| 90 | MT_GET_DATA_ACK(DT_AUDIO, NULL, 0); | ||
| 91 | #endif | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | case DT_BACKLIGHT: { | ||
| 95 | #ifdef BACKLIGHT_ENABLE | ||
| 96 | uint8_t backlight_bytes[1] = {eeprom_read_byte(EECONFIG_BACKLIGHT)}; | ||
| 97 | MT_GET_DATA_ACK(DT_BACKLIGHT, backlight_bytes, 1); | ||
| 98 | #else | ||
| 99 | MT_GET_DATA_ACK(DT_BACKLIGHT, NULL, 0); | ||
| 100 | #endif | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | case DT_RGBLIGHT: { | ||
| 104 | #ifdef RGBLIGHT_ENABLE | ||
| 105 | uint8_t rgblight_bytes[4]; | ||
| 106 | dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes); | ||
| 107 | MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4); | ||
| 108 | #else | ||
| 109 | MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0); | ||
| 110 | #endif | ||
| 111 | break; | ||
| 112 | } | ||
| 113 | case DT_KEYMAP_OPTIONS: { | ||
| 114 | uint8_t keymap_bytes[1] = {eeconfig_read_keymap()}; | ||
| 115 | MT_GET_DATA_ACK(DT_KEYMAP_OPTIONS, keymap_bytes, 1); | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | case DT_KEYMAP_SIZE: { | ||
| 119 | uint8_t keymap_size[2] = {MATRIX_ROWS, MATRIX_COLS}; | ||
| 120 | MT_GET_DATA_ACK(DT_KEYMAP_SIZE, keymap_size, 2); | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | // This may be too much | ||
| 124 | // case DT_KEYMAP: { | ||
| 125 | // uint8_t keymap_data[MATRIX_ROWS * MATRIX_COLS * 4 + 3]; | ||
| 126 | // keymap_data[0] = data[2]; | ||
| 127 | // keymap_data[1] = MATRIX_ROWS; | ||
| 128 | // keymap_data[2] = MATRIX_COLS; | ||
| 129 | // for (int i = 0; i < MATRIX_ROWS; i++) { | ||
| 130 | // for (int j = 0; j < MATRIX_COLS; j++) { | ||
| 131 | // keymap_data[3 + (i*MATRIX_COLS*2) + (j*2)] = pgm_read_word(&keymaps[data[2]][i][j]) >> 8; | ||
| 132 | // keymap_data[3 + (i*MATRIX_COLS*2) + (j*2) + 1] = pgm_read_word(&keymaps[data[2]][i][j]) & 0xFF; | ||
| 133 | // } | ||
| 134 | // } | ||
| 135 | // MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, MATRIX_ROWS * MATRIX_COLS * 4 + 3); | ||
| 136 | // // uint8_t keymap_data[5]; | ||
| 137 | // // keymap_data[0] = data[2]; | ||
| 138 | // // keymap_data[1] = data[3]; | ||
| 139 | // // keymap_data[2] = data[4]; | ||
| 140 | // // keymap_data[3] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) >> 8; | ||
| 141 | // // keymap_data[4] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) & 0xFF; | ||
| 142 | |||
| 143 | // // MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, 5); | ||
| 144 | // break; | ||
| 145 | // } | ||
| 146 | default: | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | break; | ||
| 150 | case MT_SET_DATA_ACK: | ||
| 151 | case MT_GET_DATA_ACK: | ||
| 152 | break; | ||
| 153 | case MT_SEND_DATA: | ||
| 154 | break; | ||
| 155 | case MT_SEND_DATA_ACK: | ||
| 156 | break; | ||
| 157 | case MT_EXE_ACTION: | ||
| 158 | break; | ||
| 159 | case MT_EXE_ACTION_ACK: | ||
| 160 | break; | ||
| 161 | case MT_TYPE_ERROR: | ||
| 162 | break; | ||
| 163 | default:; // command not recognised | ||
| 164 | SEND_BYTES(MT_TYPE_ERROR, DT_NONE, data, length); | ||
| 165 | break; | ||
| 166 | |||
| 167 | // #ifdef RGBLIGHT_ENABLE | ||
| 168 | // case 0x27: ; // RGB LED functions | ||
| 169 | // switch (*data++) { | ||
| 170 | // case 0x00: ; // Update HSV | ||
| 171 | // rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]); | ||
| 172 | // break; | ||
| 173 | // case 0x01: ; // Update RGB | ||
| 174 | // break; | ||
| 175 | // case 0x02: ; // Update mode | ||
| 176 | // rgblight_mode(data[0]); | ||
| 177 | // break; | ||
| 178 | // } | ||
| 179 | // break; | ||
| 180 | // #endif | ||
| 181 | } | ||
| 182 | } | ||
diff --git a/quantum/api.h b/quantum/api.h deleted file mode 100644 index 0a30e9d6c..000000000 --- a/quantum/api.h +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #ifdef __AVR__ | ||
| 20 | # include "lufa.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | enum MESSAGE_TYPE { | ||
| 24 | MT_GET_DATA = 0x10, // Get data from keyboard | ||
| 25 | MT_GET_DATA_ACK = 0x11, // returned data to process (ACK) | ||
| 26 | MT_SET_DATA = 0x20, // Set data on keyboard | ||
| 27 | MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK) | ||
| 28 | MT_SEND_DATA = 0x30, // Sending data/action from keyboard | ||
| 29 | MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK) | ||
| 30 | MT_EXE_ACTION = 0x40, // executing actions on keyboard | ||
| 31 | MT_EXE_ACTION_ACK = 0x41, // return confirmation/value (ACK) | ||
| 32 | MT_TYPE_ERROR = 0x80 // type not recognised (ACK) | ||
| 33 | }; | ||
| 34 | |||
| 35 | enum DATA_TYPE { DT_NONE = 0x00, DT_HANDSHAKE, DT_DEFAULT_LAYER, DT_CURRENT_LAYER, DT_KEYMAP_OPTIONS, DT_BACKLIGHT, DT_RGBLIGHT, DT_UNICODE, DT_DEBUG, DT_AUDIO, DT_QUANTUM_ACTION, DT_KEYBOARD_ACTION, DT_USER_ACTION, DT_KEYMAP_SIZE, DT_KEYMAP }; | ||
| 36 | |||
| 37 | void dword_to_bytes(uint32_t dword, uint8_t* bytes); | ||
| 38 | uint32_t bytes_to_dword(uint8_t* bytes, uint8_t index); | ||
| 39 | |||
| 40 | #define MT_GET_DATA(data_type, data, length) SEND_BYTES(MT_GET_DATA, data_type, data, length) | ||
| 41 | #define MT_GET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_GET_DATA_ACK, data_type, data, length) | ||
| 42 | #define MT_SET_DATA(data_type, data, length) SEND_BYTES(MT_SET_DATA, data_type, data, length) | ||
| 43 | #define MT_SET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SET_DATA_ACK, data_type, data, length) | ||
| 44 | #define MT_SEND_DATA(data_type, data, length) SEND_BYTES(MT_SEND_DATA, data_type, data, length) | ||
| 45 | #define MT_SEND_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SEND_DATA_ACK, data_type, data, length) | ||
| 46 | #define MT_EXE_ACTION(data_type, data, length) SEND_BYTES(MT_EXE_ACTION, data_type, data, length) | ||
| 47 | #define MT_EXE_ACTION_ACK(data_type, data, length) SEND_BYTES(MT_EXE_ACTION_ACK, data_type, data, length) | ||
| 48 | |||
| 49 | void process_api(uint16_t length, uint8_t* data); | ||
| 50 | |||
| 51 | __attribute__((weak)) bool process_api_quantum(uint8_t length, uint8_t* data); | ||
| 52 | |||
| 53 | __attribute__((weak)) bool process_api_keyboard(uint8_t length, uint8_t* data); | ||
| 54 | |||
| 55 | __attribute__((weak)) bool process_api_user(uint8_t length, uint8_t* data); | ||
diff --git a/quantum/api/api_sysex.c b/quantum/api/api_sysex.c deleted file mode 100644 index 07c90cf80..000000000 --- a/quantum/api/api_sysex.c +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert, Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #include "api_sysex.h" | ||
| 17 | #include "sysex_tools.h" | ||
| 18 | #include "print.h" | ||
| 19 | #include "qmk_midi.h" | ||
| 20 | |||
| 21 | void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t* bytes, uint16_t length) { | ||
| 22 | // SEND_STRING("\nTX: "); | ||
| 23 | // for (uint8_t i = 0; i < length; i++) { | ||
| 24 | // send_byte(bytes[i]); | ||
| 25 | // SEND_STRING(" "); | ||
| 26 | // } | ||
| 27 | if (length > API_SYSEX_MAX_SIZE) { | ||
| 28 | xprintf("Sysex msg too big %d %d %d", message_type, data_type, length); | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | |||
| 32 | // The buffer size required is calculated as the following | ||
| 33 | // API_SYSEX_MAX_SIZE is the maximum length | ||
| 34 | // In addition to that we have a two byte message header consisting of the message_type and data_type | ||
| 35 | // This has to be encoded with an additional overhead of one byte for every starting 7 bytes | ||
| 36 | // We just add one extra byte in case it's not divisible by 7 | ||
| 37 | // Then we have an unencoded header consisting of 4 bytes | ||
| 38 | // Plus a one byte terminator | ||
| 39 | const unsigned message_header = 2; | ||
| 40 | const unsigned unencoded_message = API_SYSEX_MAX_SIZE + message_header; | ||
| 41 | const unsigned encoding_overhead = unencoded_message / 7 + 1; | ||
| 42 | const unsigned encoded_size = unencoded_message + encoding_overhead; | ||
| 43 | const unsigned unencoded_header = 4; | ||
| 44 | const unsigned terminator = 1; | ||
| 45 | const unsigned buffer_size = encoded_size + unencoded_header + terminator; | ||
| 46 | uint8_t buffer[encoded_size + unencoded_header + terminator]; | ||
| 47 | // The unencoded header | ||
| 48 | buffer[0] = 0xF0; | ||
| 49 | buffer[1] = 0x00; | ||
| 50 | buffer[2] = 0x00; | ||
| 51 | buffer[3] = 0x00; | ||
| 52 | |||
| 53 | // We copy the message to the end of the array, this way we can do an inplace encoding, using the same | ||
| 54 | // buffer for both input and output | ||
| 55 | const unsigned message_size = length + message_header; | ||
| 56 | uint8_t* unencoded_start = buffer + buffer_size - message_size; | ||
| 57 | uint8_t* ptr = unencoded_start; | ||
| 58 | *(ptr++) = message_type; | ||
| 59 | *(ptr++) = data_type; | ||
| 60 | memcpy(ptr, bytes, length); | ||
| 61 | |||
| 62 | unsigned encoded_length = sysex_encode(buffer + unencoded_header, unencoded_start, message_size); | ||
| 63 | unsigned final_size = unencoded_header + encoded_length + terminator; | ||
| 64 | buffer[final_size - 1] = 0xF7; | ||
| 65 | midi_send_array(&midi_device, final_size, buffer); | ||
| 66 | |||
| 67 | // SEND_STRING("\nTD: "); | ||
| 68 | // for (uint8_t i = 0; i < encoded_length + 5; i++) { | ||
| 69 | // send_byte(buffer[i]); | ||
| 70 | // SEND_STRING(" "); | ||
| 71 | // } | ||
| 72 | } | ||
diff --git a/quantum/api/api_sysex.h b/quantum/api/api_sysex.h deleted file mode 100644 index eb0a18848..000000000 --- a/quantum/api/api_sysex.h +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "api.h" | ||
| 20 | |||
| 21 | #define API_SYSEX_MAX_SIZE 32 | ||
| 22 | |||
| 23 | void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t* bytes, uint16_t length); | ||
| 24 | |||
| 25 | #define SEND_BYTES(mt, dt, b, l) send_bytes_sysex(mt, dt, b, l) | ||
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h index 56b9158a1..290d461f5 100644 --- a/quantum/audio/audio.h +++ b/quantum/audio/audio.h | |||
| @@ -26,17 +26,12 @@ | |||
| 26 | 26 | ||
| 27 | #if defined(__AVR__) | 27 | #if defined(__AVR__) |
| 28 | # include <avr/io.h> | 28 | # include <avr/io.h> |
| 29 | # if defined(AUDIO_DRIVER_PWM) | ||
| 30 | # include "driver_avr_pwm.h" | ||
| 31 | # endif | ||
| 32 | #endif | 29 | #endif |
| 33 | 30 | ||
| 34 | #if defined(PROTOCOL_CHIBIOS) | 31 | #if defined(AUDIO_DRIVER_PWM) |
| 35 | # if defined(AUDIO_DRIVER_PWM) | 32 | # include "audio_pwm.h" |
| 36 | # include "driver_chibios_pwm.h" | 33 | #elif defined(AUDIO_DRIVER_DAC) |
| 37 | # elif defined(AUDIO_DRIVER_DAC) | 34 | # include "audio_dac.h" |
| 38 | # include "driver_chibios_dac.h" | ||
| 39 | # endif | ||
| 40 | #endif | 35 | #endif |
| 41 | 36 | ||
| 42 | typedef union { | 37 | typedef union { |
diff --git a/quantum/audio/driver_avr_pwm.h b/quantum/audio/driver_avr_pwm.h deleted file mode 100644 index d6eb3571d..000000000 --- a/quantum/audio/driver_avr_pwm.h +++ /dev/null | |||
| @@ -1,17 +0,0 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #pragma once | ||
diff --git a/quantum/audio/driver_avr_pwm_hardware.c b/quantum/audio/driver_avr_pwm_hardware.c deleted file mode 100644 index df03a4558..000000000 --- a/quantum/audio/driver_avr_pwm_hardware.c +++ /dev/null | |||
| @@ -1,332 +0,0 @@ | |||
| 1 | /* Copyright 2016 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #if defined(__AVR__) | ||
| 19 | # include <avr/pgmspace.h> | ||
| 20 | # include <avr/interrupt.h> | ||
| 21 | # include <avr/io.h> | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #include "audio.h" | ||
| 25 | |||
| 26 | extern bool playing_note; | ||
| 27 | extern bool playing_melody; | ||
| 28 | extern uint8_t note_timbre; | ||
| 29 | |||
| 30 | #define CPU_PRESCALER 8 | ||
| 31 | |||
| 32 | /* | ||
| 33 | Audio Driver: PWM | ||
| 34 | |||
| 35 | drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4. | ||
| 36 | |||
| 37 | the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3 | ||
| 38 | and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1 | ||
| 39 | |||
| 40 | alternatively, the PWM pins on PORTB can be used as only/primary speaker | ||
| 41 | */ | ||
| 42 | |||
| 43 | #if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5) | ||
| 44 | # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options." | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6) | ||
| 48 | # define AUDIO1_PIN_SET | ||
| 49 | # define AUDIO1_TIMSKx TIMSK3 | ||
| 50 | # define AUDIO1_TCCRxA TCCR3A | ||
| 51 | # define AUDIO1_TCCRxB TCCR3B | ||
| 52 | # define AUDIO1_ICRx ICR3 | ||
| 53 | # define AUDIO1_WGMx0 WGM30 | ||
| 54 | # define AUDIO1_WGMx1 WGM31 | ||
| 55 | # define AUDIO1_WGMx2 WGM32 | ||
| 56 | # define AUDIO1_WGMx3 WGM33 | ||
| 57 | # define AUDIO1_CSx0 CS30 | ||
| 58 | # define AUDIO1_CSx1 CS31 | ||
| 59 | # define AUDIO1_CSx2 CS32 | ||
| 60 | |||
| 61 | # if (AUDIO_PIN == C6) | ||
| 62 | # define AUDIO1_COMxy0 COM3A0 | ||
| 63 | # define AUDIO1_COMxy1 COM3A1 | ||
| 64 | # define AUDIO1_OCIExy OCIE3A | ||
| 65 | # define AUDIO1_OCRxy OCR3A | ||
| 66 | # define AUDIO1_PIN C6 | ||
| 67 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect | ||
| 68 | # elif (AUDIO_PIN == C5) | ||
| 69 | # define AUDIO1_COMxy0 COM3B0 | ||
| 70 | # define AUDIO1_COMxy1 COM3B1 | ||
| 71 | # define AUDIO1_OCIExy OCIE3B | ||
| 72 | # define AUDIO1_OCRxy OCR3B | ||
| 73 | # define AUDIO1_PIN C5 | ||
| 74 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect | ||
| 75 | # elif (AUDIO_PIN == C4) | ||
| 76 | # define AUDIO1_COMxy0 COM3C0 | ||
| 77 | # define AUDIO1_COMxy1 COM3C1 | ||
| 78 | # define AUDIO1_OCIExy OCIE3C | ||
| 79 | # define AUDIO1_OCRxy OCR3C | ||
| 80 | # define AUDIO1_PIN C4 | ||
| 81 | # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect | ||
| 82 | # endif | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT) | ||
| 86 | # error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense." | ||
| 87 | #endif | ||
| 88 | |||
| 89 | #if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6))) | ||
| 90 | # error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported." | ||
| 91 | #endif | ||
| 92 | |||
| 93 | #if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7) | ||
| 94 | # error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported." | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5) | ||
| 98 | # define AUDIO2_PIN_SET | ||
| 99 | # define AUDIO2_TIMSKx TIMSK1 | ||
| 100 | # define AUDIO2_TCCRxA TCCR1A | ||
| 101 | # define AUDIO2_TCCRxB TCCR1B | ||
| 102 | # define AUDIO2_ICRx ICR1 | ||
| 103 | # define AUDIO2_WGMx0 WGM10 | ||
| 104 | # define AUDIO2_WGMx1 WGM11 | ||
| 105 | # define AUDIO2_WGMx2 WGM12 | ||
| 106 | # define AUDIO2_WGMx3 WGM13 | ||
| 107 | # define AUDIO2_CSx0 CS10 | ||
| 108 | # define AUDIO2_CSx1 CS11 | ||
| 109 | # define AUDIO2_CSx2 CS12 | ||
| 110 | |||
| 111 | # if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5) | ||
| 112 | # define AUDIO2_COMxy0 COM1A0 | ||
| 113 | # define AUDIO2_COMxy1 COM1A1 | ||
| 114 | # define AUDIO2_OCIExy OCIE1A | ||
| 115 | # define AUDIO2_OCRxy OCR1A | ||
| 116 | # define AUDIO2_PIN B5 | ||
| 117 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect | ||
| 118 | # elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6) | ||
| 119 | # define AUDIO2_COMxy0 COM1B0 | ||
| 120 | # define AUDIO2_COMxy1 COM1B1 | ||
| 121 | # define AUDIO2_OCIExy OCIE1B | ||
| 122 | # define AUDIO2_OCRxy OCR1B | ||
| 123 | # define AUDIO2_PIN B6 | ||
| 124 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect | ||
| 125 | # elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7) | ||
| 126 | # define AUDIO2_COMxy0 COM1C0 | ||
| 127 | # define AUDIO2_COMxy1 COM1C1 | ||
| 128 | # define AUDIO2_OCIExy OCIE1C | ||
| 129 | # define AUDIO2_OCRxy OCR1C | ||
| 130 | # define AUDIO2_PIN B7 | ||
| 131 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect | ||
| 132 | # elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__) | ||
| 133 | # pragma message "Audio support for ATmega32A is experimental and can cause crashes." | ||
| 134 | # undef AUDIO2_TIMSKx | ||
| 135 | # define AUDIO2_TIMSKx TIMSK | ||
| 136 | # define AUDIO2_COMxy0 COM1A0 | ||
| 137 | # define AUDIO2_COMxy1 COM1A1 | ||
| 138 | # define AUDIO2_OCIExy OCIE1A | ||
| 139 | # define AUDIO2_OCRxy OCR1A | ||
| 140 | # define AUDIO2_PIN D5 | ||
| 141 | # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect | ||
| 142 | # endif | ||
| 143 | #endif | ||
| 144 | |||
| 145 | // C6 seems to be the assumed default by many existing keyboard - but sill warn the user | ||
| 146 | #if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET) | ||
| 147 | # pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)" | ||
| 148 | // TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define | ||
| 149 | #endif | ||
| 150 | // ----------------------------------------------------------------------------- | ||
| 151 | |||
| 152 | #ifdef AUDIO1_PIN_SET | ||
| 153 | static float channel_1_frequency = 0.0f; | ||
| 154 | void channel_1_set_frequency(float freq) { | ||
| 155 | if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0 | ||
| 156 | { | ||
| 157 | // disable the output, but keep the pwm-ISR going (with the previous | ||
| 158 | // frequency) so the audio-state keeps getting updated | ||
| 159 | // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet | ||
| 160 | AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0)); | ||
| 161 | return; | ||
| 162 | } else { | ||
| 163 | AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode | ||
| 164 | } | ||
| 165 | |||
| 166 | channel_1_frequency = freq; | ||
| 167 | |||
| 168 | // set pwm period | ||
| 169 | AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
| 170 | // and duty cycle | ||
| 171 | AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100); | ||
| 172 | } | ||
| 173 | |||
| 174 | void channel_1_start(void) { | ||
| 175 | // enable timer-counter ISR | ||
| 176 | AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy); | ||
| 177 | // enable timer-counter output | ||
| 178 | AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); | ||
| 179 | } | ||
| 180 | |||
| 181 | void channel_1_stop(void) { | ||
| 182 | // disable timer-counter ISR | ||
| 183 | AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy); | ||
| 184 | // disable timer-counter output | ||
| 185 | AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0)); | ||
| 186 | } | ||
| 187 | #endif | ||
| 188 | |||
| 189 | #ifdef AUDIO2_PIN_SET | ||
| 190 | static float channel_2_frequency = 0.0f; | ||
| 191 | void channel_2_set_frequency(float freq) { | ||
| 192 | if (freq == 0.0f) { | ||
| 193 | AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0)); | ||
| 194 | return; | ||
| 195 | } else { | ||
| 196 | AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1); | ||
| 197 | } | ||
| 198 | |||
| 199 | channel_2_frequency = freq; | ||
| 200 | |||
| 201 | AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER)); | ||
| 202 | AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100); | ||
| 203 | } | ||
| 204 | |||
| 205 | float channel_2_get_frequency(void) { return channel_2_frequency; } | ||
| 206 | |||
| 207 | void channel_2_start(void) { | ||
| 208 | AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy); | ||
| 209 | AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1); | ||
| 210 | } | ||
| 211 | |||
| 212 | void channel_2_stop(void) { | ||
| 213 | AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy); | ||
| 214 | AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0)); | ||
| 215 | } | ||
| 216 | #endif | ||
| 217 | |||
| 218 | void audio_driver_initialize() { | ||
| 219 | #ifdef AUDIO1_PIN_SET | ||
| 220 | channel_1_stop(); | ||
| 221 | setPinOutput(AUDIO1_PIN); | ||
| 222 | #endif | ||
| 223 | |||
| 224 | #ifdef AUDIO2_PIN_SET | ||
| 225 | channel_2_stop(); | ||
| 226 | setPinOutput(AUDIO2_PIN); | ||
| 227 | #endif | ||
| 228 | |||
| 229 | // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B | ||
| 230 | // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation | ||
| 231 | // OC3A -- PC6 | ||
| 232 | // OC3B -- PC5 | ||
| 233 | // OC3C -- PC4 | ||
| 234 | // OC1A -- PB5 | ||
| 235 | // OC1B -- PB6 | ||
| 236 | // OC1C -- PB7 | ||
| 237 | |||
| 238 | // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A) | ||
| 239 | // OCR3A - PC6 | ||
| 240 | // OCR3B - PC5 | ||
| 241 | // OCR3C - PC4 | ||
| 242 | // OCR1A - PB5 | ||
| 243 | // OCR1B - PB6 | ||
| 244 | // OCR1C - PB7 | ||
| 245 | |||
| 246 | // Clock Select (CS3n) = 0b010 = Clock / 8 | ||
| 247 | #ifdef AUDIO1_PIN_SET | ||
| 248 | // initialize timer-counter | ||
| 249 | AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0); | ||
| 250 | AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0); | ||
| 251 | #endif | ||
| 252 | |||
| 253 | #ifdef AUDIO2_PIN_SET | ||
| 254 | AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0); | ||
| 255 | AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0); | ||
| 256 | #endif | ||
| 257 | } | ||
| 258 | |||
| 259 | void audio_driver_stop() { | ||
| 260 | #ifdef AUDIO1_PIN_SET | ||
| 261 | channel_1_stop(); | ||
| 262 | #endif | ||
| 263 | |||
| 264 | #ifdef AUDIO2_PIN_SET | ||
| 265 | channel_2_stop(); | ||
| 266 | #endif | ||
| 267 | } | ||
| 268 | |||
| 269 | void audio_driver_start(void) { | ||
| 270 | #ifdef AUDIO1_PIN_SET | ||
| 271 | channel_1_start(); | ||
| 272 | if (playing_note) { | ||
| 273 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 274 | } | ||
| 275 | #endif | ||
| 276 | |||
| 277 | #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET) | ||
| 278 | channel_2_start(); | ||
| 279 | if (playing_note) { | ||
| 280 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 281 | } | ||
| 282 | #endif | ||
| 283 | } | ||
| 284 | |||
| 285 | static volatile uint32_t isr_counter = 0; | ||
| 286 | #ifdef AUDIO1_PIN_SET | ||
| 287 | ISR(AUDIO1_TIMERx_COMPy_vect) { | ||
| 288 | isr_counter++; | ||
| 289 | if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return; | ||
| 290 | |||
| 291 | isr_counter = 0; | ||
| 292 | bool state_changed = audio_update_state(); | ||
| 293 | |||
| 294 | if (!playing_note && !playing_melody) { | ||
| 295 | channel_1_stop(); | ||
| 296 | # ifdef AUDIO2_PIN_SET | ||
| 297 | channel_2_stop(); | ||
| 298 | # endif | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | |||
| 302 | if (state_changed) { | ||
| 303 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 304 | # ifdef AUDIO2_PIN_SET | ||
| 305 | if (audio_get_number_of_active_tones() > 1) { | ||
| 306 | channel_2_set_frequency(audio_get_processed_frequency(1)); | ||
| 307 | } else { | ||
| 308 | channel_2_stop(); | ||
| 309 | } | ||
| 310 | # endif | ||
| 311 | } | ||
| 312 | } | ||
| 313 | #endif | ||
| 314 | |||
| 315 | #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET) | ||
| 316 | ISR(AUDIO2_TIMERx_COMPy_vect) { | ||
| 317 | isr_counter++; | ||
| 318 | if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return; | ||
| 319 | |||
| 320 | isr_counter = 0; | ||
| 321 | bool state_changed = audio_update_state(); | ||
| 322 | |||
| 323 | if (!playing_note && !playing_melody) { | ||
| 324 | channel_2_stop(); | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (state_changed) { | ||
| 329 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | #endif | ||
diff --git a/quantum/audio/driver_chibios_dac.h b/quantum/audio/driver_chibios_dac.h deleted file mode 100644 index 07cd622ea..000000000 --- a/quantum/audio/driver_chibios_dac.h +++ /dev/null | |||
| @@ -1,126 +0,0 @@ | |||
| 1 | /* Copyright 2019 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #ifndef A4 | ||
| 20 | # define A4 PAL_LINE(GPIOA, 4) | ||
| 21 | #endif | ||
| 22 | #ifndef A5 | ||
| 23 | # define A5 PAL_LINE(GPIOA, 5) | ||
| 24 | #endif | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Size of the dac_buffer arrays. All must be the same size. | ||
| 28 | */ | ||
| 29 | #define AUDIO_DAC_BUFFER_SIZE 256U | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Highest value allowed sample value. | ||
| 33 | |||
| 34 | * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U; | ||
| 35 | * lower values adjust the peak-voltage aka volume down. | ||
| 36 | * adjusting this value has only an effect on a sample-buffer whose values are | ||
| 37 | * are NOT pregenerated - see square-wave | ||
| 38 | */ | ||
| 39 | #ifndef AUDIO_DAC_SAMPLE_MAX | ||
| 40 | # define AUDIO_DAC_SAMPLE_MAX 4095U | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH) | ||
| 44 | # define AUDIO_DAC_QUALITY_SANE_MINIMUM | ||
| 45 | #endif | ||
| 46 | |||
| 47 | /** | ||
| 48 | * These presets allow you to quickly switch between quality settings for | ||
| 49 | * the DAC. The sample rate and maximum number of simultaneous tones roughly | ||
| 50 | * has an inverse relationship - slightly higher sample rates may be possible. | ||
| 51 | * | ||
| 52 | * NOTE: a high sample-rate results in a higher cpu-load, which might lead to | ||
| 53 | * (audible) discontinuities and/or starve other processes of cpu-time | ||
| 54 | * (like RGB-led back-lighting, ...) | ||
| 55 | */ | ||
| 56 | #ifdef AUDIO_DAC_QUALITY_VERY_LOW | ||
| 57 | # define AUDIO_DAC_SAMPLE_RATE 11025U | ||
| 58 | # define AUDIO_MAX_SIMULTANEOUS_TONES 8 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #ifdef AUDIO_DAC_QUALITY_LOW | ||
| 62 | # define AUDIO_DAC_SAMPLE_RATE 22050U | ||
| 63 | # define AUDIO_MAX_SIMULTANEOUS_TONES 4 | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifdef AUDIO_DAC_QUALITY_HIGH | ||
| 67 | # define AUDIO_DAC_SAMPLE_RATE 44100U | ||
| 68 | # define AUDIO_MAX_SIMULTANEOUS_TONES 2 | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #ifdef AUDIO_DAC_QUALITY_VERY_HIGH | ||
| 72 | # define AUDIO_DAC_SAMPLE_RATE 88200U | ||
| 73 | # define AUDIO_MAX_SIMULTANEOUS_TONES 1 | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM | ||
| 77 | /* a sane-minimum config: with a trade-off between cpu-load and tone-range | ||
| 78 | * | ||
| 79 | * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now | ||
| 80 | * aim for an even even multiple of the buffer-size, we end up with: | ||
| 81 | * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE) | ||
| 82 | * 7902/256 = 30.867 * 2 * 256 ~= 16384 | ||
| 83 | * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P) | ||
| 84 | */ | ||
| 85 | # define AUDIO_DAC_SAMPLE_RATE 16384U | ||
| 86 | # define AUDIO_MAX_SIMULTANEOUS_TONES 8 | ||
| 87 | #endif | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any | ||
| 91 | * lower will sacrifice perceptible audio quality. Any higher will limit the | ||
| 92 | * number of simultaneous tones. In most situations, a tenth (1/10) of the | ||
| 93 | * sample rate is where notes become unbearable. | ||
| 94 | */ | ||
| 95 | #ifndef AUDIO_DAC_SAMPLE_RATE | ||
| 96 | # define AUDIO_DAC_SAMPLE_RATE 44100U | ||
| 97 | #endif | ||
| 98 | |||
| 99 | /** | ||
| 100 | * The number of tones that can be played simultaneously. If too high a value | ||
| 101 | * is used here, the keyboard will freeze and glitch-out when that many tones | ||
| 102 | * are being played. | ||
| 103 | */ | ||
| 104 | #ifndef AUDIO_MAX_SIMULTANEOUS_TONES | ||
| 105 | # define AUDIO_MAX_SIMULTANEOUS_TONES 2 | ||
| 106 | #endif | ||
| 107 | |||
| 108 | /** | ||
| 109 | * The default value of the DAC when not playing anything. Certain hardware | ||
| 110 | * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here. | ||
| 111 | * Since multiple added sine waves tend to oscillate around the midpoint, | ||
| 112 | * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a | ||
| 113 | * reasonable default value. | ||
| 114 | */ | ||
| 115 | #ifndef AUDIO_DAC_OFF_VALUE | ||
| 116 | # define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2 | ||
| 117 | #endif | ||
| 118 | |||
| 119 | #if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX | ||
| 120 | # error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX" | ||
| 121 | #endif | ||
| 122 | |||
| 123 | /** | ||
| 124 | *user overridable sample generation/processing | ||
| 125 | */ | ||
| 126 | uint16_t dac_value_generate(void); | ||
diff --git a/quantum/audio/driver_chibios_dac_additive.c b/quantum/audio/driver_chibios_dac_additive.c deleted file mode 100644 index db304adb8..000000000 --- a/quantum/audio/driver_chibios_dac_additive.c +++ /dev/null | |||
| @@ -1,335 +0,0 @@ | |||
| 1 | /* Copyright 2016-2019 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "audio.h" | ||
| 19 | #include <ch.h> | ||
| 20 | #include <hal.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | Audio Driver: DAC | ||
| 24 | |||
| 25 | which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA | ||
| 26 | |||
| 27 | it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate' | ||
| 28 | |||
| 29 | this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis | ||
| 30 | */ | ||
| 31 | |||
| 32 | #if !defined(AUDIO_PIN) | ||
| 33 | # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options." | ||
| 34 | #endif | ||
| 35 | #if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 36 | # pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though." | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #if !defined(AUDIO_PIN_ALT) | ||
| 40 | // no ALT pin defined is valid, but the c-ifs below need some value set | ||
| 41 | # define AUDIO_PIN_ALT PAL_NOLINE | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID) | ||
| 45 | # define AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
| 49 | /* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0 | ||
| 50 | */ | ||
| 51 | static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 52 | // 256 values, max 4095 | ||
| 53 | 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe, | ||
| 54 | 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1}; | ||
| 55 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE | ||
| 56 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE | ||
| 57 | static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 58 | // 256 values, max 4095 | ||
| 59 | 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf, | ||
| 60 | 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20}; | ||
| 61 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE | ||
| 62 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE | ||
| 63 | static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 64 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and | ||
| 65 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half | ||
| 66 | }; | ||
| 67 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE | ||
| 68 | /* | ||
| 69 | // four steps: 0, 1/3, 2/3 and 1 | ||
| 70 | static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 71 | [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0, | ||
| 72 | [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3, | ||
| 73 | [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3, | ||
| 74 | [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX, | ||
| 75 | } | ||
| 76 | */ | ||
| 77 | #ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID | ||
| 78 | static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, | ||
| 79 | 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 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, 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}; | ||
| 80 | #endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID | ||
| 81 | |||
| 82 | static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE}; | ||
| 83 | |||
| 84 | /* keep track of the sample position for for each frequency */ | ||
| 85 | static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0}; | ||
| 86 | |||
| 87 | static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0}; | ||
| 88 | static uint8_t active_tones_snapshot_length = 0; | ||
| 89 | |||
| 90 | typedef enum { | ||
| 91 | OUTPUT_SHOULD_START, | ||
| 92 | OUTPUT_RUN_NORMALLY, | ||
| 93 | // path 1: wait for zero, then change/update active tones | ||
| 94 | OUTPUT_TONES_CHANGED, | ||
| 95 | OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE, | ||
| 96 | // path 2: hardware should stop, wait for zero then turn output off = stop the timer | ||
| 97 | OUTPUT_SHOULD_STOP, | ||
| 98 | OUTPUT_REACHED_ZERO_BEFORE_OFF, | ||
| 99 | OUTPUT_OFF, | ||
| 100 | OUTPUT_OFF_1, | ||
| 101 | OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level | ||
| 102 | number_of_output_states | ||
| 103 | } output_states_t; | ||
| 104 | output_states_t state = OUTPUT_OFF_2; | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Generation of the waveform being passed to the callback. Declared weak so users | ||
| 108 | * can override it with their own wave-forms/noises. | ||
| 109 | */ | ||
| 110 | __attribute__((weak)) uint16_t dac_value_generate(void) { | ||
| 111 | // DAC is running/asking for values but snapshot length is zero -> must be playing a pause | ||
| 112 | if (active_tones_snapshot_length == 0) { | ||
| 113 | return AUDIO_DAC_OFF_VALUE; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* doing additive wave synthesis over all currently playing tones = adding up | ||
| 117 | * sine-wave-samples for each frequency, scaled by the number of active tones | ||
| 118 | */ | ||
| 119 | uint16_t value = 0; | ||
| 120 | float frequency = 0.0f; | ||
| 121 | |||
| 122 | for (uint8_t i = 0; i < active_tones_snapshot_length; i++) { | ||
| 123 | /* Note: a user implementation does not have to rely on the active_tones_snapshot, but | ||
| 124 | * could directly query the active frequencies through audio_get_processed_frequency */ | ||
| 125 | frequency = active_tones_snapshot[i]; | ||
| 126 | |||
| 127 | dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3; | ||
| 128 | /*Note: the 2/3 are necessary to get the correct frequencies on the | ||
| 129 | * DAC output (as measured with an oscilloscope), since the gpt | ||
| 130 | * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback | ||
| 131 | * is called twice per conversion.*/ | ||
| 132 | |||
| 133 | dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE); | ||
| 134 | |||
| 135 | // Wavetable generation/lookup | ||
| 136 | uint16_t dac_i = (uint16_t)dac_if[i]; | ||
| 137 | |||
| 138 | #if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) | ||
| 139 | value += dac_buffer_sine[dac_i] / active_tones_snapshot_length; | ||
| 140 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) | ||
| 141 | value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length; | ||
| 142 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID) | ||
| 143 | value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length; | ||
| 144 | #elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) | ||
| 145 | value += dac_buffer_square[dac_i] / active_tones_snapshot_length; | ||
| 146 | #endif | ||
| 147 | /* | ||
| 148 | // SINE | ||
| 149 | value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3; | ||
| 150 | // TRIANGLE | ||
| 151 | value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3; | ||
| 152 | // SQUARE | ||
| 153 | value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3; | ||
| 154 | //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P | ||
| 155 | */ | ||
| 156 | |||
| 157 | // STAIRS (mostly usefully as test-pattern) | ||
| 158 | // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length; | ||
| 159 | } | ||
| 160 | |||
| 161 | return value; | ||
| 162 | } | ||
| 163 | |||
| 164 | /** | ||
| 165 | * DAC streaming callback. Does all of the main computing for playing songs. | ||
| 166 | * | ||
| 167 | * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'. | ||
| 168 | */ | ||
| 169 | static void dac_end(DACDriver *dacp) { | ||
| 170 | dacsample_t *sample_p = (dacp)->samples; | ||
| 171 | |||
| 172 | // work on the other half of the buffer | ||
| 173 | if (dacIsBufferComplete(dacp)) { | ||
| 174 | sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index' | ||
| 175 | } | ||
| 176 | |||
| 177 | for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) { | ||
| 178 | if (OUTPUT_OFF <= state) { | ||
| 179 | sample_p[s] = AUDIO_DAC_OFF_VALUE; | ||
| 180 | continue; | ||
| 181 | } else { | ||
| 182 | sample_p[s] = dac_value_generate(); | ||
| 183 | } | ||
| 184 | |||
| 185 | /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX) | ||
| 186 | * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX | ||
| 187 | * * * | ||
| 188 | * * * | ||
| 189 | * --------------------------------------------------------- | ||
| 190 | * * * } AUDIO_DAC_SAMPLE_MAX/100 | ||
| 191 | * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE | ||
| 192 | * * * } AUDIO_DAC_SAMPLE_MAX/100 | ||
| 193 | * --------------------------------------------------------- | ||
| 194 | * * | ||
| 195 | * * * | ||
| 196 | * * * | ||
| 197 | * =====*=*================================================= 0x0 | ||
| 198 | */ | ||
| 199 | if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below | ||
| 200 | (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above | ||
| 201 | ) { | ||
| 202 | if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) { | ||
| 203 | state = OUTPUT_RUN_NORMALLY; | ||
| 204 | } else if (OUTPUT_TONES_CHANGED == state) { | ||
| 205 | state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE; | ||
| 206 | } else if (OUTPUT_SHOULD_STOP == state) { | ||
| 207 | state = OUTPUT_REACHED_ZERO_BEFORE_OFF; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover | ||
| 212 | if (OUTPUT_SHOULD_START == state) { | ||
| 213 | sample_p[s] = AUDIO_DAC_OFF_VALUE; | ||
| 214 | } | ||
| 215 | |||
| 216 | if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) { | ||
| 217 | uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones()); | ||
| 218 | active_tones_snapshot_length = 0; | ||
| 219 | // update the snapshot - once, and only on occasion that something changed; | ||
| 220 | // -> saves cpu cycles (?) | ||
| 221 | for (uint8_t i = 0; i < active_tones; i++) { | ||
| 222 | float freq = audio_get_processed_frequency(i); | ||
| 223 | if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step | ||
| 224 | active_tones_snapshot[active_tones_snapshot_length++] = freq; | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) { | ||
| 229 | state = OUTPUT_OFF; | ||
| 230 | } | ||
| 231 | if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) { | ||
| 232 | state = OUTPUT_RUN_NORMALLY; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | // update audio internal state (note position, current_note, ...) | ||
| 238 | if (audio_update_state()) { | ||
| 239 | if (OUTPUT_SHOULD_STOP != state) { | ||
| 240 | state = OUTPUT_TONES_CHANGED; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | if (OUTPUT_OFF <= state) { | ||
| 245 | if (OUTPUT_OFF_2 == state) { | ||
| 246 | // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE | ||
| 247 | gptStopTimer(&GPTD6); | ||
| 248 | } else { | ||
| 249 | state++; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | static void dac_error(DACDriver *dacp, dacerror_t err) { | ||
| 255 | (void)dacp; | ||
| 256 | (void)err; | ||
| 257 | |||
| 258 | chSysHalt("DAC failure. halp"); | ||
| 259 | } | ||
| 260 | |||
| 261 | static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3, | ||
| 262 | .callback = NULL, | ||
| 263 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 264 | .dier = 0U}; | ||
| 265 | |||
| 266 | static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
| 267 | |||
| 268 | /** | ||
| 269 | * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered | ||
| 270 | * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency | ||
| 271 | * to be a third of what we expect. | ||
| 272 | * | ||
| 273 | * Here are all the values for DAC_TRG (TSEL in the ref manual) | ||
| 274 | * TIM15_TRGO 0b011 | ||
| 275 | * TIM2_TRGO 0b100 | ||
| 276 | * TIM3_TRGO 0b001 | ||
| 277 | * TIM6_TRGO 0b000 | ||
| 278 | * TIM7_TRGO 0b010 | ||
| 279 | * EXTI9 0b110 | ||
| 280 | * SWTRIG 0b111 | ||
| 281 | */ | ||
| 282 | static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)}; | ||
| 283 | |||
| 284 | void audio_driver_initialize() { | ||
| 285 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 286 | palSetLineMode(A4, PAL_MODE_INPUT_ANALOG); | ||
| 287 | dacStart(&DACD1, &dac_conf); | ||
| 288 | } | ||
| 289 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 290 | palSetLineMode(A5, PAL_MODE_INPUT_ANALOG); | ||
| 291 | dacStart(&DACD2, &dac_conf); | ||
| 292 | } | ||
| 293 | |||
| 294 | /* enable the output buffer, to directly drive external loads with no additional circuitry | ||
| 295 | * | ||
| 296 | * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers | ||
| 297 | * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer | ||
| 298 | * Note: enabling the output buffer imparts an additional dc-offset of a couple mV | ||
| 299 | * | ||
| 300 | * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet | ||
| 301 | * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.' | ||
| 302 | */ | ||
| 303 | DACD1.params->dac->CR &= ~DAC_CR_BOFF1; | ||
| 304 | DACD2.params->dac->CR &= ~DAC_CR_BOFF2; | ||
| 305 | |||
| 306 | if (AUDIO_PIN == A4) { | ||
| 307 | dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE); | ||
| 308 | } else if (AUDIO_PIN == A5) { | ||
| 309 | dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE); | ||
| 310 | } | ||
| 311 | |||
| 312 | // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE | ||
| 313 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 314 | if (AUDIO_PIN_ALT == A4) { | ||
| 315 | dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE); | ||
| 316 | } else if (AUDIO_PIN_ALT == A5) { | ||
| 317 | dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE); | ||
| 318 | } | ||
| 319 | #endif | ||
| 320 | |||
| 321 | gptStart(&GPTD6, &gpt6cfg1); | ||
| 322 | } | ||
| 323 | |||
| 324 | void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; } | ||
| 325 | |||
| 326 | void audio_driver_start(void) { | ||
| 327 | gptStartContinuous(&GPTD6, 2U); | ||
| 328 | |||
| 329 | for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) { | ||
| 330 | dac_if[i] = 0.0f; | ||
| 331 | active_tones_snapshot[i] = 0.0f; | ||
| 332 | } | ||
| 333 | active_tones_snapshot_length = 0; | ||
| 334 | state = OUTPUT_SHOULD_START; | ||
| 335 | } | ||
diff --git a/quantum/audio/driver_chibios_dac_basic.c b/quantum/audio/driver_chibios_dac_basic.c deleted file mode 100644 index fac651350..000000000 --- a/quantum/audio/driver_chibios_dac_basic.c +++ /dev/null | |||
| @@ -1,245 +0,0 @@ | |||
| 1 | /* Copyright 2016-2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "audio.h" | ||
| 19 | #include "ch.h" | ||
| 20 | #include "hal.h" | ||
| 21 | |||
| 22 | /* | ||
| 23 | Audio Driver: DAC | ||
| 24 | |||
| 25 | which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA | ||
| 26 | |||
| 27 | this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously | ||
| 28 | OR | ||
| 29 | one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio | ||
| 30 | |||
| 31 | */ | ||
| 32 | |||
| 33 | #if !defined(AUDIO_PIN) | ||
| 34 | # pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options." | ||
| 35 | // TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here | ||
| 36 | # define AUDIO_PIN A5 | ||
| 37 | #endif | ||
| 38 | // check configuration for ONE speaker, connected to both DAC pins | ||
| 39 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT) | ||
| 40 | # error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT" | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #ifndef AUDIO_PIN_ALT | ||
| 44 | // no ALT pin defined is valid, but the c-ifs below need some value set | ||
| 45 | # define AUDIO_PIN_ALT -1 | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #if !defined(AUDIO_STATE_TIMER) | ||
| 49 | # define AUDIO_STATE_TIMER GPTD8 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | // square-wave | ||
| 53 | static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 54 | // First half is max, second half is 0 | ||
| 55 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX, | ||
| 56 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0, | ||
| 57 | }; | ||
| 58 | |||
| 59 | // square-wave | ||
| 60 | static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = { | ||
| 61 | // opposite of dac_buffer above | ||
| 62 | [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, | ||
| 63 | [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, | ||
| 64 | }; | ||
| 65 | |||
| 66 | GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE, | ||
| 67 | .callback = NULL, | ||
| 68 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 69 | .dier = 0U}; | ||
| 70 | GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE, | ||
| 71 | .callback = NULL, | ||
| 72 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 73 | .dier = 0U}; | ||
| 74 | |||
| 75 | static void gpt_audio_state_cb(GPTDriver *gptp); | ||
| 76 | GPTConfig gptStateUpdateCfg = {.frequency = 10, | ||
| 77 | .callback = gpt_audio_state_cb, | ||
| 78 | .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */ | ||
| 79 | .dier = 0U}; | ||
| 80 | |||
| 81 | static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
| 82 | static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT}; | ||
| 83 | |||
| 84 | /** | ||
| 85 | * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered | ||
| 86 | * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency | ||
| 87 | * to be a third of what we expect. | ||
| 88 | * | ||
| 89 | * Here are all the values for DAC_TRG (TSEL in the ref manual) | ||
| 90 | * TIM15_TRGO 0b011 | ||
| 91 | * TIM2_TRGO 0b100 | ||
| 92 | * TIM3_TRGO 0b001 | ||
| 93 | * TIM6_TRGO 0b000 | ||
| 94 | * TIM7_TRGO 0b010 | ||
| 95 | * EXTI9 0b110 | ||
| 96 | * SWTRIG 0b111 | ||
| 97 | */ | ||
| 98 | static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)}; | ||
| 99 | static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)}; | ||
| 100 | |||
| 101 | void channel_1_start(void) { | ||
| 102 | gptStart(&GPTD6, &gpt6cfg1); | ||
| 103 | gptStartContinuous(&GPTD6, 2U); | ||
| 104 | palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); | ||
| 105 | } | ||
| 106 | |||
| 107 | void channel_1_stop(void) { | ||
| 108 | gptStopTimer(&GPTD6); | ||
| 109 | palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 110 | palSetPad(GPIOA, 4); | ||
| 111 | } | ||
| 112 | |||
| 113 | static float channel_1_frequency = 0.0f; | ||
| 114 | void channel_1_set_frequency(float freq) { | ||
| 115 | channel_1_frequency = freq; | ||
| 116 | |||
| 117 | channel_1_stop(); | ||
| 118 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 119 | return; | ||
| 120 | |||
| 121 | gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE; | ||
| 122 | channel_1_start(); | ||
| 123 | } | ||
| 124 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
| 125 | |||
| 126 | void channel_2_start(void) { | ||
| 127 | gptStart(&GPTD7, &gpt7cfg1); | ||
| 128 | gptStartContinuous(&GPTD7, 2U); | ||
| 129 | palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); | ||
| 130 | } | ||
| 131 | |||
| 132 | void channel_2_stop(void) { | ||
| 133 | gptStopTimer(&GPTD7); | ||
| 134 | palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 135 | palSetPad(GPIOA, 5); | ||
| 136 | } | ||
| 137 | |||
| 138 | static float channel_2_frequency = 0.0f; | ||
| 139 | void channel_2_set_frequency(float freq) { | ||
| 140 | channel_2_frequency = freq; | ||
| 141 | |||
| 142 | channel_2_stop(); | ||
| 143 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 144 | return; | ||
| 145 | |||
| 146 | gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE; | ||
| 147 | channel_2_start(); | ||
| 148 | } | ||
| 149 | float channel_2_get_frequency(void) { return channel_2_frequency; } | ||
| 150 | |||
| 151 | static void gpt_audio_state_cb(GPTDriver *gptp) { | ||
| 152 | if (audio_update_state()) { | ||
| 153 | #if defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 154 | // one piezo/speaker connected to both audio pins, the generated square-waves are inverted | ||
| 155 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 156 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 157 | |||
| 158 | #else // two separate audio outputs/speakers | ||
| 159 | // primary speaker on A4, optional secondary on A5 | ||
| 160 | if (AUDIO_PIN == A4) { | ||
| 161 | channel_1_set_frequency(audio_get_processed_frequency(0)); | ||
| 162 | if (AUDIO_PIN_ALT == A5) { | ||
| 163 | if (audio_get_number_of_active_tones() > 1) { | ||
| 164 | channel_2_set_frequency(audio_get_processed_frequency(1)); | ||
| 165 | } else { | ||
| 166 | channel_2_stop(); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | // primary speaker on A5, optional secondary on A4 | ||
| 172 | if (AUDIO_PIN == A5) { | ||
| 173 | channel_2_set_frequency(audio_get_processed_frequency(0)); | ||
| 174 | if (AUDIO_PIN_ALT == A4) { | ||
| 175 | if (audio_get_number_of_active_tones() > 1) { | ||
| 176 | channel_1_set_frequency(audio_get_processed_frequency(1)); | ||
| 177 | } else { | ||
| 178 | channel_1_stop(); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | #endif | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | void audio_driver_initialize() { | ||
| 187 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 188 | palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG); | ||
| 189 | dacStart(&DACD1, &dac_conf_ch1); | ||
| 190 | |||
| 191 | // initial setup of the dac-triggering timer is still required, even | ||
| 192 | // though it gets reconfigured and restarted later on | ||
| 193 | gptStart(&GPTD6, &gpt6cfg1); | ||
| 194 | } | ||
| 195 | |||
| 196 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 197 | palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); | ||
| 198 | dacStart(&DACD2, &dac_conf_ch2); | ||
| 199 | |||
| 200 | gptStart(&GPTD7, &gpt7cfg1); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* enable the output buffer, to directly drive external loads with no additional circuitry | ||
| 204 | * | ||
| 205 | * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers | ||
| 206 | * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer | ||
| 207 | * Note: enabling the output buffer imparts an additional dc-offset of a couple mV | ||
| 208 | * | ||
| 209 | * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet | ||
| 210 | * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.' | ||
| 211 | */ | ||
| 212 | DACD1.params->dac->CR &= ~DAC_CR_BOFF1; | ||
| 213 | DACD2.params->dac->CR &= ~DAC_CR_BOFF2; | ||
| 214 | |||
| 215 | // start state-updater | ||
| 216 | gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg); | ||
| 217 | } | ||
| 218 | |||
| 219 | void audio_driver_stop(void) { | ||
| 220 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 221 | gptStopTimer(&GPTD6); | ||
| 222 | |||
| 223 | // stop the ongoing conversion and put the output in a known state | ||
| 224 | dacStopConversion(&DACD1); | ||
| 225 | dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE); | ||
| 226 | } | ||
| 227 | |||
| 228 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 229 | gptStopTimer(&GPTD7); | ||
| 230 | |||
| 231 | dacStopConversion(&DACD2); | ||
| 232 | dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE); | ||
| 233 | } | ||
| 234 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
| 235 | } | ||
| 236 | |||
| 237 | void audio_driver_start(void) { | ||
| 238 | if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) { | ||
| 239 | dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE); | ||
| 240 | } | ||
| 241 | if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) { | ||
| 242 | dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE); | ||
| 243 | } | ||
| 244 | gptStartContinuous(&AUDIO_STATE_TIMER, 2U); | ||
| 245 | } | ||
diff --git a/quantum/audio/driver_chibios_pwm.h b/quantum/audio/driver_chibios_pwm.h deleted file mode 100644 index 86cab916e..000000000 --- a/quantum/audio/driver_chibios_pwm.h +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #if !defined(AUDIO_PWM_DRIVER) | ||
| 20 | // NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1)) | ||
| 21 | # define AUDIO_PWM_DRIVER PWMD1 | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #if !defined(AUDIO_PWM_CHANNEL) | ||
| 25 | // NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4 | ||
| 26 | // default: STM32F303CC PA8+TIM1_CH1 -> 1 | ||
| 27 | # define AUDIO_PWM_CHANNEL 1 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #if !defined(AUDIO_PWM_PAL_MODE) | ||
| 31 | // pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy | ||
| 32 | // default: STM32F303CC PA8+TIM1_CH1 -> 6 | ||
| 33 | # define AUDIO_PWM_PAL_MODE 6 | ||
| 34 | #endif | ||
| 35 | |||
| 36 | #if !defined(AUDIO_STATE_TIMER) | ||
| 37 | // timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf. | ||
| 38 | // Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4) | ||
| 39 | # define AUDIO_STATE_TIMER GPTD6 | ||
| 40 | #endif | ||
diff --git a/quantum/audio/driver_chibios_pwm_hardware.c b/quantum/audio/driver_chibios_pwm_hardware.c deleted file mode 100644 index 3c7d89b29..000000000 --- a/quantum/audio/driver_chibios_pwm_hardware.c +++ /dev/null | |||
| @@ -1,144 +0,0 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | Audio Driver: PWM | ||
| 20 | |||
| 21 | the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back. | ||
| 22 | |||
| 23 | this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware. | ||
| 24 | The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function. | ||
| 25 | |||
| 26 | */ | ||
| 27 | |||
| 28 | #include "audio.h" | ||
| 29 | #include "ch.h" | ||
| 30 | #include "hal.h" | ||
| 31 | |||
| 32 | #if !defined(AUDIO_PIN) | ||
| 33 | # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" | ||
| 34 | #endif | ||
| 35 | |||
| 36 | extern bool playing_note; | ||
| 37 | extern bool playing_melody; | ||
| 38 | extern uint8_t note_timbre; | ||
| 39 | |||
| 40 | static PWMConfig pwmCFG = { | ||
| 41 | .frequency = 100000, /* PWM clock frequency */ | ||
| 42 | // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime | ||
| 43 | .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ | ||
| 44 | .callback = NULL, /* no callback, the hardware directly toggles the pin */ | ||
| 45 | .channels = | ||
| 46 | { | ||
| 47 | #if AUDIO_PWM_CHANNEL == 4 | ||
| 48 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */ | ||
| 49 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */ | ||
| 50 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */ | ||
| 51 | {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */ | ||
| 52 | #elif AUDIO_PWM_CHANNEL == 3 | ||
| 53 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 54 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 55 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */ | ||
| 56 | {PWM_OUTPUT_DISABLED, NULL} | ||
| 57 | #elif AUDIO_PWM_CHANNEL == 2 | ||
| 58 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 59 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */ | ||
| 60 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 61 | {PWM_OUTPUT_DISABLED, NULL} | ||
| 62 | #else /*fallback to CH1 */ | ||
| 63 | {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */ | ||
| 64 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 65 | {PWM_OUTPUT_DISABLED, NULL}, | ||
| 66 | {PWM_OUTPUT_DISABLED, NULL} | ||
| 67 | #endif | ||
| 68 | }, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static float channel_1_frequency = 0.0f; | ||
| 72 | void channel_1_set_frequency(float freq) { | ||
| 73 | channel_1_frequency = freq; | ||
| 74 | |||
| 75 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 76 | return; | ||
| 77 | |||
| 78 | pwmcnt_t period = (pwmCFG.frequency / freq); | ||
| 79 | pwmChangePeriod(&AUDIO_PWM_DRIVER, period); | ||
| 80 | pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, | ||
| 81 | // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH | ||
| 82 | PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); | ||
| 83 | } | ||
| 84 | |||
| 85 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
| 86 | |||
| 87 | void channel_1_start(void) { | ||
| 88 | pwmStop(&AUDIO_PWM_DRIVER); | ||
| 89 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 90 | } | ||
| 91 | |||
| 92 | void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); } | ||
| 93 | |||
| 94 | static void gpt_callback(GPTDriver *gptp); | ||
| 95 | GPTConfig gptCFG = { | ||
| 96 | /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64 | ||
| 97 | the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 | ||
| 98 | the tempo (which might vary!) is in bpm (beats per minute) | ||
| 99 | therefore: if the timer ticks away at .frequency = (60*64)Hz, | ||
| 100 | and the .interval counts from 64 downwards - audio_update_state is | ||
| 101 | called just often enough to not miss any notes | ||
| 102 | */ | ||
| 103 | .frequency = 60 * 64, | ||
| 104 | .callback = gpt_callback, | ||
| 105 | }; | ||
| 106 | |||
| 107 | void audio_driver_initialize(void) { | ||
| 108 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 109 | |||
| 110 | // connect the AUDIO_PIN to the PWM hardware | ||
| 111 | #if defined(USE_GPIOV1) // STM32F103C8 | ||
| 112 | palSetLineMode(AUDIO_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL); | ||
| 113 | #else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command) | ||
| 114 | palSetLineMode(AUDIO_PIN, PAL_STM32_MODE_ALTERNATE | PAL_STM32_ALTERNATE(AUDIO_PWM_PAL_MODE)); | ||
| 115 | #endif | ||
| 116 | |||
| 117 | gptStart(&AUDIO_STATE_TIMER, &gptCFG); | ||
| 118 | } | ||
| 119 | |||
| 120 | void audio_driver_start(void) { | ||
| 121 | channel_1_stop(); | ||
| 122 | channel_1_start(); | ||
| 123 | |||
| 124 | if (playing_note || playing_melody) { | ||
| 125 | gptStartContinuous(&AUDIO_STATE_TIMER, 64); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | void audio_driver_stop(void) { | ||
| 130 | channel_1_stop(); | ||
| 131 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* a regular timer task, that checks the note to be currently played | ||
| 135 | * and updates the pwm to output that frequency | ||
| 136 | */ | ||
| 137 | static void gpt_callback(GPTDriver *gptp) { | ||
| 138 | float freq; // TODO: freq_alt | ||
| 139 | |||
| 140 | if (audio_update_state()) { | ||
| 141 | freq = audio_get_processed_frequency(0); // freq_alt would be index=1 | ||
| 142 | channel_1_set_frequency(freq); | ||
| 143 | } | ||
| 144 | } | ||
diff --git a/quantum/audio/driver_chibios_pwm_software.c b/quantum/audio/driver_chibios_pwm_software.c deleted file mode 100644 index 15c3e98b6..000000000 --- a/quantum/audio/driver_chibios_pwm_software.c +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | /* Copyright 2020 Jack Humbert | ||
| 2 | * Copyright 2020 JohSchneider | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | Audio Driver: PWM | ||
| 20 | |||
| 21 | the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back. | ||
| 22 | |||
| 23 | this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software | ||
| 24 | - a pwm callback is used to set/clear the configured pin. | ||
| 25 | |||
| 26 | */ | ||
| 27 | #include "audio.h" | ||
| 28 | #include "ch.h" | ||
| 29 | #include "hal.h" | ||
| 30 | |||
| 31 | #if !defined(AUDIO_PIN) | ||
| 32 | # error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings" | ||
| 33 | #endif | ||
| 34 | extern bool playing_note; | ||
| 35 | extern bool playing_melody; | ||
| 36 | extern uint8_t note_timbre; | ||
| 37 | |||
| 38 | static void pwm_audio_period_callback(PWMDriver *pwmp); | ||
| 39 | static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp); | ||
| 40 | |||
| 41 | static PWMConfig pwmCFG = { | ||
| 42 | .frequency = 100000, /* PWM clock frequency */ | ||
| 43 | // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime | ||
| 44 | .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */ | ||
| 45 | .callback = pwm_audio_period_callback, | ||
| 46 | .channels = | ||
| 47 | { | ||
| 48 | // software-PWM just needs another callback on any channel | ||
| 49 | {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */ | ||
| 50 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */ | ||
| 51 | {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */ | ||
| 52 | {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */ | ||
| 53 | }, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static float channel_1_frequency = 0.0f; | ||
| 57 | void channel_1_set_frequency(float freq) { | ||
| 58 | channel_1_frequency = freq; | ||
| 59 | |||
| 60 | if (freq <= 0.0) // a pause/rest has freq=0 | ||
| 61 | return; | ||
| 62 | |||
| 63 | pwmcnt_t period = (pwmCFG.frequency / freq); | ||
| 64 | pwmChangePeriod(&AUDIO_PWM_DRIVER, period); | ||
| 65 | |||
| 66 | pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1, | ||
| 67 | // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH | ||
| 68 | PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100)); | ||
| 69 | } | ||
| 70 | |||
| 71 | float channel_1_get_frequency(void) { return channel_1_frequency; } | ||
| 72 | |||
| 73 | void channel_1_start(void) { | ||
| 74 | pwmStop(&AUDIO_PWM_DRIVER); | ||
| 75 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 76 | |||
| 77 | pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); | ||
| 78 | pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1); | ||
| 79 | } | ||
| 80 | |||
| 81 | void channel_1_stop(void) { | ||
| 82 | pwmStop(&AUDIO_PWM_DRIVER); | ||
| 83 | |||
| 84 | palClearLine(AUDIO_PIN); // leave the line low, after last note was played | ||
| 85 | |||
| 86 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 87 | palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played | ||
| 88 | #endif | ||
| 89 | } | ||
| 90 | |||
| 91 | // generate a PWM signal on any pin, not necessarily the one connected to the timer | ||
| 92 | static void pwm_audio_period_callback(PWMDriver *pwmp) { | ||
| 93 | (void)pwmp; | ||
| 94 | palClearLine(AUDIO_PIN); | ||
| 95 | |||
| 96 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 97 | palSetLine(AUDIO_PIN_ALT); | ||
| 98 | #endif | ||
| 99 | } | ||
| 100 | static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) { | ||
| 101 | (void)pwmp; | ||
| 102 | if (channel_1_frequency > 0) { | ||
| 103 | palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer | ||
| 104 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 105 | palClearLine(AUDIO_PIN_ALT); | ||
| 106 | #endif | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static void gpt_callback(GPTDriver *gptp); | ||
| 111 | GPTConfig gptCFG = { | ||
| 112 | /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64 | ||
| 113 | the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 | ||
| 114 | the tempo (which might vary!) is in bpm (beats per minute) | ||
| 115 | therefore: if the timer ticks away at .frequency = (60*64)Hz, | ||
| 116 | and the .interval counts from 64 downwards - audio_update_state is | ||
| 117 | called just often enough to not miss anything | ||
| 118 | */ | ||
| 119 | .frequency = 60 * 64, | ||
| 120 | .callback = gpt_callback, | ||
| 121 | }; | ||
| 122 | |||
| 123 | void audio_driver_initialize(void) { | ||
| 124 | pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG); | ||
| 125 | |||
| 126 | palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 127 | palClearLine(AUDIO_PIN); | ||
| 128 | |||
| 129 | #if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE) | ||
| 130 | palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL); | ||
| 131 | palClearLine(AUDIO_PIN_ALT); | ||
| 132 | #endif | ||
| 133 | |||
| 134 | pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks | ||
| 135 | pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1); | ||
| 136 | |||
| 137 | gptStart(&AUDIO_STATE_TIMER, &gptCFG); | ||
| 138 | } | ||
| 139 | |||
| 140 | void audio_driver_start(void) { | ||
| 141 | channel_1_stop(); | ||
| 142 | channel_1_start(); | ||
| 143 | |||
| 144 | if (playing_note || playing_melody) { | ||
| 145 | gptStartContinuous(&AUDIO_STATE_TIMER, 64); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | void audio_driver_stop(void) { | ||
| 150 | channel_1_stop(); | ||
| 151 | gptStopTimer(&AUDIO_STATE_TIMER); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* a regular timer task, that checks the note to be currently played | ||
| 155 | * and updates the pwm to output that frequency | ||
| 156 | */ | ||
| 157 | static void gpt_callback(GPTDriver *gptp) { | ||
| 158 | float freq; // TODO: freq_alt | ||
| 159 | |||
| 160 | if (audio_update_state()) { | ||
| 161 | freq = audio_get_processed_frequency(0); // freq_alt would be index=1 | ||
| 162 | channel_1_set_frequency(freq); | ||
| 163 | } | ||
| 164 | } | ||
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h index b54b397e1..8e80a016a 100644 --- a/quantum/audio/song_list.h +++ b/quantum/audio/song_list.h | |||
| @@ -20,11 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | #include "musical_notes.h" | 21 | #include "musical_notes.h" |
| 22 | 22 | ||
| 23 | #if __GNUC__ > 5 // don't use for older gcc compilers since check isn't supported. | 23 | #if __has_include("user_song_list.h") |
| 24 | # if __has_include("user_song_list.h") | 24 | # include "user_song_list.h" |
| 25 | # include "user_song_list.h" | 25 | #endif // if file exists |
| 26 | # endif // if file exists | ||
| 27 | #endif // __GNUC__ | ||
| 28 | 26 | ||
| 29 | #define NO_SOUND | 27 | #define NO_SOUND |
| 30 | 28 | ||
diff --git a/quantum/backlight/backlight_chibios.c b/quantum/backlight/backlight_chibios.c index 4d5a69e14..7c6edd10d 100644 --- a/quantum/backlight/backlight_chibios.c +++ b/quantum/backlight/backlight_chibios.c | |||
| @@ -8,9 +8,13 @@ | |||
| 8 | # define BACKLIGHT_LIMIT_VAL 255 | 8 | # define BACKLIGHT_LIMIT_VAL 255 |
| 9 | #endif | 9 | #endif |
| 10 | 10 | ||
| 11 | // GPIOV2 && GPIOV3 | ||
| 12 | #ifndef BACKLIGHT_PAL_MODE | 11 | #ifndef BACKLIGHT_PAL_MODE |
| 13 | # define BACKLIGHT_PAL_MODE 2 | 12 | # if defined(USE_GPIOV1) |
| 13 | # define BACKLIGHT_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL | ||
| 14 | # else | ||
| 15 | // GPIOV2 && GPIOV3 | ||
| 16 | # define BACKLIGHT_PAL_MODE 5 | ||
| 17 | # endif | ||
| 14 | #endif | 18 | #endif |
| 15 | 19 | ||
| 16 | // GENERIC | 20 | // GENERIC |
| @@ -70,7 +74,7 @@ static uint32_t rescale_limit_val(uint32_t val) { | |||
| 70 | 74 | ||
| 71 | void backlight_init_ports(void) { | 75 | void backlight_init_ports(void) { |
| 72 | #ifdef USE_GPIOV1 | 76 | #ifdef USE_GPIOV1 |
| 73 | palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); | 77 | palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), BACKLIGHT_PAL_MODE); |
| 74 | #else | 78 | #else |
| 75 | palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE)); | 79 | palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE)); |
| 76 | #endif | 80 | #endif |
diff --git a/quantum/eeconfig.c b/quantum/eeconfig.c index 92f0ac443..4c2ad2490 100644 --- a/quantum/eeconfig.c +++ b/quantum/eeconfig.c | |||
| @@ -4,11 +4,6 @@ | |||
| 4 | #include "eeconfig.h" | 4 | #include "eeconfig.h" |
| 5 | #include "action_layer.h" | 5 | #include "action_layer.h" |
| 6 | 6 | ||
| 7 | #ifdef STM32_EEPROM_ENABLE | ||
| 8 | # include <hal.h> | ||
| 9 | # include "eeprom_stm32.h" | ||
| 10 | #endif | ||
| 11 | |||
| 12 | #if defined(EEPROM_DRIVER) | 7 | #if defined(EEPROM_DRIVER) |
| 13 | # include "eeprom_driver.h" | 8 | # include "eeprom_driver.h" |
| 14 | #endif | 9 | #endif |
| @@ -43,9 +38,6 @@ __attribute__((weak)) void eeconfig_init_kb(void) { | |||
| 43 | * FIXME: needs doc | 38 | * FIXME: needs doc |
| 44 | */ | 39 | */ |
| 45 | void eeconfig_init_quantum(void) { | 40 | void eeconfig_init_quantum(void) { |
| 46 | #ifdef STM32_EEPROM_ENABLE | ||
| 47 | EEPROM_Erase(); | ||
| 48 | #endif | ||
| 49 | #if defined(EEPROM_DRIVER) | 41 | #if defined(EEPROM_DRIVER) |
| 50 | eeprom_driver_erase(); | 42 | eeprom_driver_erase(); |
| 51 | #endif | 43 | #endif |
| @@ -111,9 +103,6 @@ void eeconfig_enable(void) { eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_N | |||
| 111 | * FIXME: needs doc | 103 | * FIXME: needs doc |
| 112 | */ | 104 | */ |
| 113 | void eeconfig_disable(void) { | 105 | void eeconfig_disable(void) { |
| 114 | #ifdef STM32_EEPROM_ENABLE | ||
| 115 | EEPROM_Erase(); | ||
| 116 | #endif | ||
| 117 | #if defined(EEPROM_DRIVER) | 106 | #if defined(EEPROM_DRIVER) |
| 118 | eeprom_driver_erase(); | 107 | eeprom_driver_erase(); |
| 119 | #endif | 108 | #endif |
diff --git a/quantum/eeconfig.h b/quantum/eeconfig.h index bd39971b2..22d874273 100644 --- a/quantum/eeconfig.h +++ b/quantum/eeconfig.h | |||
| @@ -111,3 +111,29 @@ void eeconfig_update_haptic(uint32_t val); | |||
| 111 | 111 | ||
| 112 | bool eeconfig_read_handedness(void); | 112 | bool eeconfig_read_handedness(void); |
| 113 | void eeconfig_update_handedness(bool val); | 113 | void eeconfig_update_handedness(bool val); |
| 114 | |||
| 115 | #define EECONFIG_DEBOUNCE_HELPER(name, offset, config) \ | ||
| 116 | static uint8_t dirty_##name = false; \ | ||
| 117 | \ | ||
| 118 | static inline void eeconfig_init_##name(void) { \ | ||
| 119 | eeprom_read_block(&config, offset, sizeof(config)); \ | ||
| 120 | dirty_##name = false; \ | ||
| 121 | } \ | ||
| 122 | static inline void eeconfig_flush_##name(bool force) { \ | ||
| 123 | if (force || dirty_##name) { \ | ||
| 124 | eeprom_update_block(&config, offset, sizeof(config)); \ | ||
| 125 | dirty_##name = false; \ | ||
| 126 | } \ | ||
| 127 | } \ | ||
| 128 | static inline void eeconfig_flush_##name##_task(uint16_t timeout) { \ | ||
| 129 | static uint16_t flush_timer = 0; \ | ||
| 130 | if (timer_elapsed(flush_timer) > timeout) { \ | ||
| 131 | eeconfig_flush_##name(false); \ | ||
| 132 | flush_timer = timer_read(); \ | ||
| 133 | } \ | ||
| 134 | } \ | ||
| 135 | static inline void eeconfig_flag_##name(bool v) { dirty_##name |= v; } \ | ||
| 136 | static inline void eeconfig_write_##name(typeof(config) conf) { \ | ||
| 137 | memcpy(&config, &conf, sizeof(config)); \ | ||
| 138 | eeconfig_flag_##name(true); \ | ||
| 139 | } | ||
diff --git a/quantum/keyboard.c b/quantum/keyboard.c index b98fc64e4..f2a0889c1 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c | |||
| @@ -43,9 +43,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 43 | #ifdef SERIAL_MOUSE_ENABLE | 43 | #ifdef SERIAL_MOUSE_ENABLE |
| 44 | # include "serial_mouse.h" | 44 | # include "serial_mouse.h" |
| 45 | #endif | 45 | #endif |
| 46 | #ifdef ADB_MOUSE_ENABLE | ||
| 47 | # include "adb.h" | ||
| 48 | #endif | ||
| 49 | #ifdef RGBLIGHT_ENABLE | 46 | #ifdef RGBLIGHT_ENABLE |
| 50 | # include "rgblight.h" | 47 | # include "rgblight.h" |
| 51 | #endif | 48 | #endif |
| @@ -61,12 +58,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 61 | #ifdef STENO_ENABLE | 58 | #ifdef STENO_ENABLE |
| 62 | # include "process_steno.h" | 59 | # include "process_steno.h" |
| 63 | #endif | 60 | #endif |
| 64 | #ifdef SERIAL_LINK_ENABLE | ||
| 65 | # include "serial_link/system/serial_link.h" | ||
| 66 | #endif | ||
| 67 | #ifdef VISUALIZER_ENABLE | ||
| 68 | # include "visualizer/visualizer.h" | ||
| 69 | #endif | ||
| 70 | #ifdef POINTING_DEVICE_ENABLE | 61 | #ifdef POINTING_DEVICE_ENABLE |
| 71 | # include "pointing_device.h" | 62 | # include "pointing_device.h" |
| 72 | #endif | 63 | #endif |
| @@ -76,12 +67,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 76 | #ifdef JOYSTICK_ENABLE | 67 | #ifdef JOYSTICK_ENABLE |
| 77 | # include "process_joystick.h" | 68 | # include "process_joystick.h" |
| 78 | #endif | 69 | #endif |
| 70 | #ifdef PROGRAMMABLE_BUTTON_ENABLE | ||
| 71 | # include "programmable_button.h" | ||
| 72 | #endif | ||
| 79 | #ifdef HD44780_ENABLE | 73 | #ifdef HD44780_ENABLE |
| 80 | # include "hd44780.h" | 74 | # include "hd44780.h" |
| 81 | #endif | 75 | #endif |
| 82 | #ifdef QWIIC_ENABLE | ||
| 83 | # include "qwiic.h" | ||
| 84 | #endif | ||
| 85 | #ifdef OLED_ENABLE | 76 | #ifdef OLED_ENABLE |
| 86 | # include "oled_driver.h" | 77 | # include "oled_driver.h" |
| 87 | #endif | 78 | #endif |
| @@ -97,9 +88,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 97 | #ifdef DIP_SWITCH_ENABLE | 88 | #ifdef DIP_SWITCH_ENABLE |
| 98 | # include "dip_switch.h" | 89 | # include "dip_switch.h" |
| 99 | #endif | 90 | #endif |
| 100 | #ifdef STM32_EEPROM_ENABLE | ||
| 101 | # include "eeprom_stm32.h" | ||
| 102 | #endif | ||
| 103 | #ifdef EEPROM_DRIVER | 91 | #ifdef EEPROM_DRIVER |
| 104 | # include "eeprom_driver.h" | 92 | # include "eeprom_driver.h" |
| 105 | #endif | 93 | #endif |
| @@ -246,9 +234,6 @@ void keyboard_setup(void) { | |||
| 246 | disable_jtag(); | 234 | disable_jtag(); |
| 247 | #endif | 235 | #endif |
| 248 | print_set_sendchar(sendchar); | 236 | print_set_sendchar(sendchar); |
| 249 | #ifdef STM32_EEPROM_ENABLE | ||
| 250 | EEPROM_Init(); | ||
| 251 | #endif | ||
| 252 | #ifdef EEPROM_DRIVER | 237 | #ifdef EEPROM_DRIVER |
| 253 | eeprom_driver_init(); | 238 | eeprom_driver_init(); |
| 254 | #endif | 239 | #endif |
| @@ -316,9 +301,6 @@ void keyboard_init(void) { | |||
| 316 | #if defined(CRC_ENABLE) | 301 | #if defined(CRC_ENABLE) |
| 317 | crc_init(); | 302 | crc_init(); |
| 318 | #endif | 303 | #endif |
| 319 | #ifdef QWIIC_ENABLE | ||
| 320 | qwiic_init(); | ||
| 321 | #endif | ||
| 322 | #ifdef OLED_ENABLE | 304 | #ifdef OLED_ENABLE |
| 323 | oled_init(OLED_ROTATION_0); | 305 | oled_init(OLED_ROTATION_0); |
| 324 | #endif | 306 | #endif |
| @@ -331,9 +313,6 @@ void keyboard_init(void) { | |||
| 331 | #ifdef SERIAL_MOUSE_ENABLE | 313 | #ifdef SERIAL_MOUSE_ENABLE |
| 332 | serial_mouse_init(); | 314 | serial_mouse_init(); |
| 333 | #endif | 315 | #endif |
| 334 | #ifdef ADB_MOUSE_ENABLE | ||
| 335 | adb_mouse_init(); | ||
| 336 | #endif | ||
| 337 | #ifdef BACKLIGHT_ENABLE | 316 | #ifdef BACKLIGHT_ENABLE |
| 338 | backlight_init(); | 317 | backlight_init(); |
| 339 | #endif | 318 | #endif |
| @@ -384,7 +363,6 @@ void switch_events(uint8_t row, uint8_t col, bool pressed) { | |||
| 384 | * | 363 | * |
| 385 | * * scan matrix | 364 | * * scan matrix |
| 386 | * * handle mouse movements | 365 | * * handle mouse movements |
| 387 | * * run visualizer code | ||
| 388 | * * handle midi commands | 366 | * * handle midi commands |
| 389 | * * light LEDs | 367 | * * light LEDs |
| 390 | * | 368 | * |
| @@ -473,10 +451,6 @@ MATRIX_LOOP_END: | |||
| 473 | if (encoders_changed) last_encoder_activity_trigger(); | 451 | if (encoders_changed) last_encoder_activity_trigger(); |
| 474 | #endif | 452 | #endif |
| 475 | 453 | ||
| 476 | #ifdef QWIIC_ENABLE | ||
| 477 | qwiic_task(); | ||
| 478 | #endif | ||
| 479 | |||
| 480 | #ifdef OLED_ENABLE | 454 | #ifdef OLED_ENABLE |
| 481 | oled_task(); | 455 | oled_task(); |
| 482 | # if OLED_TIMEOUT > 0 | 456 | # if OLED_TIMEOUT > 0 |
| @@ -514,18 +488,6 @@ MATRIX_LOOP_END: | |||
| 514 | serial_mouse_task(); | 488 | serial_mouse_task(); |
| 515 | #endif | 489 | #endif |
| 516 | 490 | ||
| 517 | #ifdef ADB_MOUSE_ENABLE | ||
| 518 | adb_mouse_task(); | ||
| 519 | #endif | ||
| 520 | |||
| 521 | #ifdef SERIAL_LINK_ENABLE | ||
| 522 | serial_link_update(); | ||
| 523 | #endif | ||
| 524 | |||
| 525 | #ifdef VISUALIZER_ENABLE | ||
| 526 | visualizer_update(default_layer_state, layer_state, visualizer_get_mods(), host_keyboard_leds()); | ||
| 527 | #endif | ||
| 528 | |||
| 529 | #ifdef POINTING_DEVICE_ENABLE | 491 | #ifdef POINTING_DEVICE_ENABLE |
| 530 | pointing_device_task(); | 492 | pointing_device_task(); |
| 531 | #endif | 493 | #endif |
| @@ -548,6 +510,10 @@ MATRIX_LOOP_END: | |||
| 548 | digitizer_task(); | 510 | digitizer_task(); |
| 549 | #endif | 511 | #endif |
| 550 | 512 | ||
| 513 | #ifdef PROGRAMMABLE_BUTTON_ENABLE | ||
| 514 | programmable_button_send(); | ||
| 515 | #endif | ||
| 516 | |||
| 551 | // update LED | 517 | // update LED |
| 552 | if (led_status != host_keyboard_leds()) { | 518 | if (led_status != host_keyboard_leds()) { |
| 553 | led_status = host_keyboard_leds(); | 519 | led_status = host_keyboard_leds(); |
diff --git a/quantum/keymap_extras/keymap_turkish_f.h b/quantum/keymap_extras/keymap_turkish_f.h index 226f8cbeb..f86ef2154 100644 --- a/quantum/keymap_extras/keymap_turkish_f.h +++ b/quantum/keymap_extras/keymap_turkish_f.h | |||
| @@ -111,7 +111,7 @@ | |||
| 111 | #define TR_LPRN S(TR_8) // ( | 111 | #define TR_LPRN S(TR_8) // ( |
| 112 | #define TR_RPRN S(TR_9) // ) | 112 | #define TR_RPRN S(TR_9) // ) |
| 113 | #define TR_EQL S(TR_0) // = | 113 | #define TR_EQL S(TR_0) // = |
| 114 | #define TR_QUES S(TR_ASTR) // ? | 114 | #define TR_QUES S(TR_SLSH) // ? |
| 115 | #define TR_UNDS S(TR_MINS) // _ | 115 | #define TR_UNDS S(TR_MINS) // _ |
| 116 | // Row 4 | 116 | // Row 4 |
| 117 | #define TR_RABK S(TR_LABK) // > | 117 | #define TR_RABK S(TR_LABK) // > |
diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c index 50510e49a..85556d157 100644 --- a/quantum/led_matrix/led_matrix.c +++ b/quantum/led_matrix/led_matrix.c | |||
| @@ -33,14 +33,6 @@ const led_point_t k_led_matrix_center = {112, 32}; | |||
| 33 | const led_point_t k_led_matrix_center = LED_MATRIX_CENTER; | 33 | const led_point_t k_led_matrix_center = LED_MATRIX_CENTER; |
| 34 | #endif | 34 | #endif |
| 35 | 35 | ||
| 36 | // clang-format off | ||
| 37 | #ifndef LED_MATRIX_IMMEDIATE_EEPROM | ||
| 38 | # define led_eeconfig_update(v) led_update_eeprom |= v | ||
| 39 | #else | ||
| 40 | # define led_eeconfig_update(v) if (v) eeconfig_update_led_matrix() | ||
| 41 | #endif | ||
| 42 | // clang-format on | ||
| 43 | |||
| 44 | // Generic effect runners | 36 | // Generic effect runners |
| 45 | #include "led_matrix_runners.inc" | 37 | #include "led_matrix_runners.inc" |
| 46 | 38 | ||
| @@ -107,7 +99,6 @@ last_hit_t g_last_hit_tracker; | |||
| 107 | 99 | ||
| 108 | // internals | 100 | // internals |
| 109 | static bool suspend_state = false; | 101 | static bool suspend_state = false; |
| 110 | static bool led_update_eeprom = false; | ||
| 111 | static uint8_t led_last_enable = UINT8_MAX; | 102 | static uint8_t led_last_enable = UINT8_MAX; |
| 112 | static uint8_t led_last_effect = UINT8_MAX; | 103 | static uint8_t led_last_effect = UINT8_MAX; |
| 113 | static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false}; | 104 | static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false}; |
| @@ -127,9 +118,9 @@ static last_hit_t last_hit_buffer; | |||
| 127 | const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT; | 118 | const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT; |
| 128 | #endif | 119 | #endif |
| 129 | 120 | ||
| 130 | void eeconfig_read_led_matrix(void) { eeprom_read_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); } | 121 | EECONFIG_DEBOUNCE_HELPER(led_matrix, EECONFIG_LED_MATRIX, led_matrix_eeconfig); |
| 131 | 122 | ||
| 132 | void eeconfig_update_led_matrix(void) { eeprom_update_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); } | 123 | void eeconfig_update_led_matrix(void) { eeconfig_flush_led_matrix(true); } |
| 133 | 124 | ||
| 134 | void eeconfig_update_led_matrix_default(void) { | 125 | void eeconfig_update_led_matrix_default(void) { |
| 135 | dprintf("eeconfig_update_led_matrix_default\n"); | 126 | dprintf("eeconfig_update_led_matrix_default\n"); |
| @@ -138,7 +129,7 @@ void eeconfig_update_led_matrix_default(void) { | |||
| 138 | led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL; | 129 | led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL; |
| 139 | led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD; | 130 | led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD; |
| 140 | led_matrix_eeconfig.flags = LED_FLAG_ALL; | 131 | led_matrix_eeconfig.flags = LED_FLAG_ALL; |
| 141 | eeconfig_update_led_matrix(); | 132 | eeconfig_flush_led_matrix(true); |
| 142 | } | 133 | } |
| 143 | 134 | ||
| 144 | void eeconfig_debug_led_matrix(void) { | 135 | void eeconfig_debug_led_matrix(void) { |
| @@ -279,9 +270,8 @@ static void led_task_timers(void) { | |||
| 279 | } | 270 | } |
| 280 | 271 | ||
| 281 | static void led_task_sync(void) { | 272 | static void led_task_sync(void) { |
| 273 | eeconfig_flush_led_matrix(false); | ||
| 282 | // next task | 274 | // next task |
| 283 | if (led_update_eeprom) eeconfig_update_led_matrix(); | ||
| 284 | led_update_eeprom = false; | ||
| 285 | if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING; | 275 | if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING; |
| 286 | } | 276 | } |
| 287 | 277 | ||
| @@ -449,7 +439,7 @@ void led_matrix_init(void) { | |||
| 449 | eeconfig_update_led_matrix_default(); | 439 | eeconfig_update_led_matrix_default(); |
| 450 | } | 440 | } |
| 451 | 441 | ||
| 452 | eeconfig_read_led_matrix(); | 442 | eeconfig_init_led_matrix(); |
| 453 | if (!led_matrix_eeconfig.mode) { | 443 | if (!led_matrix_eeconfig.mode) { |
| 454 | dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n"); | 444 | dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n"); |
| 455 | eeconfig_update_led_matrix_default(); | 445 | eeconfig_update_led_matrix_default(); |
| @@ -472,7 +462,7 @@ bool led_matrix_get_suspend_state(void) { return suspend_state; } | |||
| 472 | void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) { | 462 | void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) { |
| 473 | led_matrix_eeconfig.enable ^= 1; | 463 | led_matrix_eeconfig.enable ^= 1; |
| 474 | led_task_state = STARTING; | 464 | led_task_state = STARTING; |
| 475 | led_eeconfig_update(write_to_eeprom); | 465 | eeconfig_flag_led_matrix(write_to_eeprom); |
| 476 | dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable); | 466 | dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable); |
| 477 | } | 467 | } |
| 478 | void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); } | 468 | void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); } |
| @@ -480,7 +470,7 @@ void led_matrix_toggle(void) { led_matrix_toggle_eeprom_helper(true); } | |||
| 480 | 470 | ||
| 481 | void led_matrix_enable(void) { | 471 | void led_matrix_enable(void) { |
| 482 | led_matrix_enable_noeeprom(); | 472 | led_matrix_enable_noeeprom(); |
| 483 | led_eeconfig_update(true); | 473 | eeconfig_flag_led_matrix(true); |
| 484 | } | 474 | } |
| 485 | 475 | ||
| 486 | void led_matrix_enable_noeeprom(void) { | 476 | void led_matrix_enable_noeeprom(void) { |
| @@ -490,7 +480,7 @@ void led_matrix_enable_noeeprom(void) { | |||
| 490 | 480 | ||
| 491 | void led_matrix_disable(void) { | 481 | void led_matrix_disable(void) { |
| 492 | led_matrix_disable_noeeprom(); | 482 | led_matrix_disable_noeeprom(); |
| 493 | led_eeconfig_update(true); | 483 | eeconfig_flag_led_matrix(true); |
| 494 | } | 484 | } |
| 495 | 485 | ||
| 496 | void led_matrix_disable_noeeprom(void) { | 486 | void led_matrix_disable_noeeprom(void) { |
| @@ -512,7 +502,7 @@ void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { | |||
| 512 | led_matrix_eeconfig.mode = mode; | 502 | led_matrix_eeconfig.mode = mode; |
| 513 | } | 503 | } |
| 514 | led_task_state = STARTING; | 504 | led_task_state = STARTING; |
| 515 | led_eeconfig_update(write_to_eeprom); | 505 | eeconfig_flag_led_matrix(write_to_eeprom); |
| 516 | dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode); | 506 | dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode); |
| 517 | } | 507 | } |
| 518 | void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); } | 508 | void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); } |
| @@ -539,7 +529,7 @@ void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) { | |||
| 539 | return; | 529 | return; |
| 540 | } | 530 | } |
| 541 | led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val; | 531 | led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val; |
| 542 | led_eeconfig_update(write_to_eeprom); | 532 | eeconfig_flag_led_matrix(write_to_eeprom); |
| 543 | dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val); | 533 | dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val); |
| 544 | } | 534 | } |
| 545 | void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); } | 535 | void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); } |
| @@ -557,7 +547,7 @@ void led_matrix_decrease_val(void) { led_matrix_decrease_val_helper(true); } | |||
| 557 | 547 | ||
| 558 | void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { | 548 | void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { |
| 559 | led_matrix_eeconfig.speed = speed; | 549 | led_matrix_eeconfig.speed = speed; |
| 560 | led_eeconfig_update(write_to_eeprom); | 550 | eeconfig_flag_led_matrix(write_to_eeprom); |
| 561 | dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed); | 551 | dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed); |
| 562 | } | 552 | } |
| 563 | void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); } | 553 | void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); } |
diff --git a/quantum/led_matrix/led_matrix_drivers.c b/quantum/led_matrix/led_matrix_drivers.c index 1d46b2c50..2157619a0 100644 --- a/quantum/led_matrix/led_matrix_drivers.c +++ b/quantum/led_matrix/led_matrix_drivers.c | |||
| @@ -26,128 +26,123 @@ | |||
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #if defined(IS31FL3731) || defined(IS31FL3733) | 28 | #if defined(IS31FL3731) || defined(IS31FL3733) |
| 29 | |||
| 30 | # include "i2c_master.h" | 29 | # include "i2c_master.h" |
| 31 | 30 | ||
| 32 | static void init(void) { | 31 | static void init(void) { |
| 33 | i2c_init(); | 32 | i2c_init(); |
| 34 | # ifdef IS31FL3731 | 33 | |
| 35 | # ifdef LED_DRIVER_ADDR_1 | 34 | # if defined(IS31FL3731) |
| 36 | IS31FL3731_init(LED_DRIVER_ADDR_1); | 35 | IS31FL3731_init(LED_DRIVER_ADDR_1); |
| 37 | # endif | 36 | # if defined(LED_DRIVER_ADDR_2) |
| 38 | # ifdef LED_DRIVER_ADDR_2 | ||
| 39 | IS31FL3731_init(LED_DRIVER_ADDR_2); | 37 | IS31FL3731_init(LED_DRIVER_ADDR_2); |
| 40 | # endif | 38 | # if defined(LED_DRIVER_ADDR_3) |
| 41 | # ifdef LED_DRIVER_ADDR_3 | ||
| 42 | IS31FL3731_init(LED_DRIVER_ADDR_3); | 39 | IS31FL3731_init(LED_DRIVER_ADDR_3); |
| 43 | # endif | 40 | # if defined(LED_DRIVER_ADDR_4) |
| 44 | # ifdef LED_DRIVER_ADDR_4 | ||
| 45 | IS31FL3731_init(LED_DRIVER_ADDR_4); | 41 | IS31FL3731_init(LED_DRIVER_ADDR_4); |
| 46 | # endif | 42 | # endif |
| 47 | # else | ||
| 48 | # ifdef LED_DRIVER_ADDR_1 | ||
| 49 | # ifndef LED_DRIVER_SYNC_1 | ||
| 50 | # define LED_DRIVER_SYNC_1 0 | ||
| 51 | # endif | 43 | # endif |
| 52 | IS31FL3733_init(LED_DRIVER_ADDR_1, LED_DRIVER_SYNC_1); | ||
| 53 | # endif | 44 | # endif |
| 54 | # ifdef LED_DRIVER_ADDR_2 | 45 | |
| 55 | # ifndef LED_DRIVER_SYNC_2 | 46 | # elif defined(IS31FL3733) |
| 47 | # if !defined(LED_DRIVER_SYNC_1) | ||
| 48 | # define LED_DRIVER_SYNC_1 0 | ||
| 49 | # endif | ||
| 50 | IS31FL3733_init(LED_DRIVER_ADDR_1, LED_DRIVER_SYNC_1); | ||
| 51 | # if defined(LED_DRIVER_ADDR_2) | ||
| 52 | # if !defined(LED_DRIVER_SYNC_2) | ||
| 56 | # define LED_DRIVER_SYNC_2 0 | 53 | # define LED_DRIVER_SYNC_2 0 |
| 57 | # endif | 54 | # endif |
| 58 | IS31FL3733_init(LED_DRIVER_ADDR_2, LED_DRIVER_SYNC_2); | 55 | IS31FL3733_init(LED_DRIVER_ADDR_2, LED_DRIVER_SYNC_2); |
| 59 | # endif | 56 | # if defined(LED_DRIVER_ADDR_3) |
| 60 | # ifdef LED_DRIVER_ADDR_3 | 57 | # if !defined(LED_DRIVER_SYNC_3) |
| 61 | # ifndef LED_DRIVER_SYNC_3 | 58 | # define LED_DRIVER_SYNC_3 0 |
| 62 | # define LED_DRIVER_SYNC_3 0 | 59 | # endif |
| 63 | # endif | ||
| 64 | IS31FL3733_init(LED_DRIVER_ADDR_3, LED_DRIVER_SYNC_3); | 60 | IS31FL3733_init(LED_DRIVER_ADDR_3, LED_DRIVER_SYNC_3); |
| 65 | # endif | 61 | # if defined(LED_DRIVER_ADDR_4) |
| 66 | # ifdef LED_DRIVER_ADDR_4 | 62 | # if !defined(LED_DRIVER_SYNC_4) |
| 67 | # ifndef LED_DRIVER_SYNC_4 | 63 | # define LED_DRIVER_SYNC_4 0 |
| 68 | # define LED_DRIVER_SYNC_4 0 | 64 | # endif |
| 69 | # endif | ||
| 70 | IS31FL3733_init(LED_DRIVER_ADDR_4, LED_DRIVER_SYNC_4); | 65 | IS31FL3733_init(LED_DRIVER_ADDR_4, LED_DRIVER_SYNC_4); |
| 66 | # endif | ||
| 67 | # endif | ||
| 71 | # endif | 68 | # endif |
| 72 | # endif | 69 | # endif |
| 73 | 70 | ||
| 74 | for (int index = 0; index < DRIVER_LED_TOTAL; index++) { | 71 | for (int index = 0; index < DRIVER_LED_TOTAL; index++) { |
| 75 | # ifdef IS31FL3731 | 72 | # if defined(IS31FL3731) |
| 76 | IS31FL3731_set_led_control_register(index, true); | 73 | IS31FL3731_set_led_control_register(index, true); |
| 77 | # else | 74 | # elif defined(IS31FL3733) |
| 78 | IS31FL3733_set_led_control_register(index, true); | 75 | IS31FL3733_set_led_control_register(index, true); |
| 79 | # endif | 76 | # endif |
| 80 | } | 77 | } |
| 78 | |||
| 81 | // This actually updates the LED drivers | 79 | // This actually updates the LED drivers |
| 82 | # ifdef IS31FL3731 | 80 | # if defined(IS31FL3731) |
| 83 | # ifdef LED_DRIVER_ADDR_1 | ||
| 84 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_1, 0); | 81 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_1, 0); |
| 85 | # endif | 82 | # if defined(LED_DRIVER_ADDR_2) |
| 86 | # ifdef LED_DRIVER_ADDR_2 | ||
| 87 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_2, 1); | 83 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_2, 1); |
| 88 | # endif | 84 | # if defined(LED_DRIVER_ADDR_3) |
| 89 | # ifdef LED_DRIVER_ADDR_3 | ||
| 90 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_3, 2); | 85 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_3, 2); |
| 91 | # endif | 86 | # if defined(LED_DRIVER_ADDR_4) |
| 92 | # ifdef LED_DRIVER_ADDR_4 | ||
| 93 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_4, 3); | 87 | IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_4, 3); |
| 88 | # endif | ||
| 89 | # endif | ||
| 94 | # endif | 90 | # endif |
| 95 | # else | 91 | |
| 96 | # ifdef LED_DRIVER_ADDR_1 | 92 | # elif defined(IS31FL3733) |
| 97 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_1, 0); | 93 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_1, 0); |
| 98 | # endif | 94 | # if defined(LED_DRIVER_ADDR_2) |
| 99 | # ifdef LED_DRIVER_ADDR_2 | ||
| 100 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_2, 1); | 95 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_2, 1); |
| 101 | # endif | 96 | # if defined(LED_DRIVER_ADDR_3) |
| 102 | # ifdef LED_DRIVER_ADDR_3 | ||
| 103 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_3, 2); | 97 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_3, 2); |
| 104 | # endif | 98 | # if defined(LED_DRIVER_ADDR_4) |
| 105 | # ifdef LED_DRIVER_ADDR_4 | ||
| 106 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_4, 3); | 99 | IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_4, 3); |
| 100 | # endif | ||
| 101 | # endif | ||
| 107 | # endif | 102 | # endif |
| 108 | # endif | 103 | # endif |
| 109 | } | 104 | } |
| 110 | 105 | ||
| 106 | # if defined(IS31FL3731) | ||
| 111 | static void flush(void) { | 107 | static void flush(void) { |
| 112 | # ifdef IS31FL3731 | ||
| 113 | # ifdef LED_DRIVER_ADDR_1 | ||
| 114 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_1, 0); | 108 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_1, 0); |
| 115 | # endif | 109 | # if defined(LED_DRIVER_ADDR_2) |
| 116 | # ifdef LED_DRIVER_ADDR_2 | ||
| 117 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_2, 1); | 110 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_2, 1); |
| 118 | # endif | 111 | # if defined(LED_DRIVER_ADDR_3) |
| 119 | # ifdef LED_DRIVER_ADDR_3 | ||
| 120 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_3, 2); | 112 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_3, 2); |
| 121 | # endif | 113 | # if defined(LED_DRIVER_ADDR_4) |
| 122 | # ifdef LED_DRIVER_ADDR_4 | ||
| 123 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_4, 3); | 114 | IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_4, 3); |
| 115 | # endif | ||
| 116 | # endif | ||
| 124 | # endif | 117 | # endif |
| 125 | # else | 118 | } |
| 126 | # ifdef LED_DRIVER_ADDR_1 | 119 | |
| 120 | const led_matrix_driver_t led_matrix_driver = { | ||
| 121 | .init = init, | ||
| 122 | .flush = flush, | ||
| 123 | .set_value = IS31FL3731_set_value, | ||
| 124 | .set_value_all = IS31FL3731_set_value_all, | ||
| 125 | }; | ||
| 126 | |||
| 127 | # elif defined(IS31FL3733) | ||
| 128 | static void flush(void) { | ||
| 127 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_1, 0); | 129 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_1, 0); |
| 128 | # endif | 130 | # if defined(LED_DRIVER_ADDR_2) |
| 129 | # ifdef LED_DRIVER_ADDR_2 | ||
| 130 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_2, 1); | 131 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_2, 1); |
| 131 | # endif | 132 | # if defined(LED_DRIVER_ADDR_3) |
| 132 | # ifdef LED_DRIVER_ADDR_3 | ||
| 133 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_3, 2); | 133 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_3, 2); |
| 134 | # endif | 134 | # if defined(LED_DRIVER_ADDR_4) |
| 135 | # ifdef LED_DRIVER_ADDR_4 | ||
| 136 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_4, 3); | 135 | IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_4, 3); |
| 136 | # endif | ||
| 137 | # endif | ||
| 137 | # endif | 138 | # endif |
| 138 | # endif | ||
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | const led_matrix_driver_t led_matrix_driver = { | 141 | const led_matrix_driver_t led_matrix_driver = { |
| 142 | .init = init, | 142 | .init = init, |
| 143 | .flush = flush, | 143 | .flush = flush, |
| 144 | # ifdef IS31FL3731 | ||
| 145 | .set_value = IS31FL3731_set_value, | ||
| 146 | .set_value_all = IS31FL3731_set_value_all, | ||
| 147 | # else | ||
| 148 | .set_value = IS31FL3733_set_value, | 144 | .set_value = IS31FL3733_set_value, |
| 149 | .set_value_all = IS31FL3733_set_value_all, | 145 | .set_value_all = IS31FL3733_set_value_all, |
| 150 | # endif | ||
| 151 | }; | 146 | }; |
| 152 | 147 | # endif | |
| 153 | #endif | 148 | #endif |
diff --git a/quantum/matrix.c b/quantum/matrix.c index 33586c431..4fbcc2419 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c | |||
| @@ -288,10 +288,8 @@ void matrix_init(void) { | |||
| 288 | matrix_init_pins(); | 288 | matrix_init_pins(); |
| 289 | 289 | ||
| 290 | // initialize matrix state: all keys off | 290 | // initialize matrix state: all keys off |
| 291 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | 291 | memset(matrix, 0, sizeof(matrix)); |
| 292 | raw_matrix[i] = 0; | 292 | memset(raw_matrix, 0, sizeof(raw_matrix)); |
| 293 | matrix[i] = 0; | ||
| 294 | } | ||
| 295 | 293 | ||
| 296 | debounce_init(ROWS_PER_HAND); | 294 | debounce_init(ROWS_PER_HAND); |
| 297 | 295 | ||
| @@ -312,24 +310,22 @@ __attribute__((weak)) bool transport_master_if_connected(matrix_row_t master_mat | |||
| 312 | bool matrix_post_scan(void) { | 310 | bool matrix_post_scan(void) { |
| 313 | bool changed = false; | 311 | bool changed = false; |
| 314 | if (is_keyboard_master()) { | 312 | if (is_keyboard_master()) { |
| 313 | static bool last_connected = false; | ||
| 315 | matrix_row_t slave_matrix[ROWS_PER_HAND] = {0}; | 314 | matrix_row_t slave_matrix[ROWS_PER_HAND] = {0}; |
| 316 | if (transport_master_if_connected(matrix + thisHand, slave_matrix)) { | 315 | if (transport_master_if_connected(matrix + thisHand, slave_matrix)) { |
| 317 | for (int i = 0; i < ROWS_PER_HAND; ++i) { | 316 | changed = memcmp(matrix + thatHand, slave_matrix, sizeof(slave_matrix)) != 0; |
| 318 | if (matrix[thatHand + i] != slave_matrix[i]) { | ||
| 319 | matrix[thatHand + i] = slave_matrix[i]; | ||
| 320 | changed = true; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | } else { | ||
| 324 | // reset other half if disconnected | ||
| 325 | for (int i = 0; i < ROWS_PER_HAND; ++i) { | ||
| 326 | matrix[thatHand + i] = 0; | ||
| 327 | slave_matrix[i] = 0; | ||
| 328 | } | ||
| 329 | 317 | ||
| 318 | last_connected = true; | ||
| 319 | } else if (last_connected) { | ||
| 320 | // reset other half when disconnected | ||
| 321 | memset(slave_matrix, 0, sizeof(slave_matrix)); | ||
| 330 | changed = true; | 322 | changed = true; |
| 323 | |||
| 324 | last_connected = false; | ||
| 331 | } | 325 | } |
| 332 | 326 | ||
| 327 | if (changed) memcpy(matrix + thatHand, slave_matrix, sizeof(slave_matrix)); | ||
| 328 | |||
| 333 | matrix_scan_quantum(); | 329 | matrix_scan_quantum(); |
| 334 | } else { | 330 | } else { |
| 335 | transport_slave(matrix + thatHand, matrix + thisHand); | 331 | transport_slave(matrix + thatHand, matrix + thisHand); |
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk index f7eaeec8a..7c4a617af 100644 --- a/quantum/mcu_selection.mk +++ b/quantum/mcu_selection.mk | |||
| @@ -81,7 +81,7 @@ ifneq ($(findstring MK20DX256, $(MCU)),) | |||
| 81 | BOARD ?= PJRC_TEENSY_3_1 | 81 | BOARD ?= PJRC_TEENSY_3_1 |
| 82 | endif | 82 | endif |
| 83 | 83 | ||
| 84 | ifneq ($(findstring MK66F18, $(MCU)),) | 84 | ifneq ($(findstring MK66FX1M0, $(MCU)),) |
| 85 | # Cortex version | 85 | # Cortex version |
| 86 | MCU = cortex-m4 | 86 | MCU = cortex-m4 |
| 87 | 87 | ||
| @@ -138,6 +138,11 @@ ifneq ($(findstring STM32F042, $(MCU)),) | |||
| 138 | 138 | ||
| 139 | # UF2 settings | 139 | # UF2 settings |
| 140 | UF2_FAMILY ?= STM32F0 | 140 | UF2_FAMILY ?= STM32F0 |
| 141 | |||
| 142 | # Stack sizes: Since this chip has limited RAM capacity, the stack area needs to be reduced. | ||
| 143 | # This ensures that the EEPROM page buffer fits into RAM | ||
| 144 | USE_PROCESS_STACKSIZE = 0x600 | ||
| 145 | USE_EXCEPTIONS_STACKSIZE = 0x300 | ||
| 141 | endif | 146 | endif |
| 142 | 147 | ||
| 143 | ifneq ($(findstring STM32F072, $(MCU)),) | 148 | ifneq ($(findstring STM32F072, $(MCU)),) |
| @@ -273,6 +278,38 @@ ifneq ($(findstring STM32F401, $(MCU)),) | |||
| 273 | UF2_FAMILY ?= STM32F4 | 278 | UF2_FAMILY ?= STM32F4 |
| 274 | endif | 279 | endif |
| 275 | 280 | ||
| 281 | ifneq ($(findstring STM32F405, $(MCU)),) | ||
| 282 | # Cortex version | ||
| 283 | MCU = cortex-m4 | ||
| 284 | |||
| 285 | # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7 | ||
| 286 | ARMV = 7 | ||
| 287 | |||
| 288 | ## chip/board settings | ||
| 289 | # - the next two should match the directories in | ||
| 290 | # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES) | ||
| 291 | MCU_FAMILY = STM32 | ||
| 292 | MCU_SERIES = STM32F4xx | ||
| 293 | |||
| 294 | # Linker script to use | ||
| 295 | # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/ | ||
| 296 | # or <keyboard_dir>/ld/ | ||
| 297 | MCU_LDSCRIPT ?= STM32F405xG | ||
| 298 | |||
| 299 | # Startup code to use | ||
| 300 | # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/ | ||
| 301 | MCU_STARTUP ?= stm32f4xx | ||
| 302 | |||
| 303 | # Board: it should exist either in <chibios>/os/hal/boards/, | ||
| 304 | # <keyboard_dir>/boards/, or drivers/boards/ | ||
| 305 | BOARD ?= GENERIC_STM32_F405XG | ||
| 306 | |||
| 307 | USE_FPU ?= yes | ||
| 308 | |||
| 309 | # UF2 settings | ||
| 310 | UF2_FAMILY ?= STM32F4 | ||
| 311 | endif | ||
| 312 | |||
| 276 | ifneq ($(findstring STM32F407, $(MCU)),) | 313 | ifneq ($(findstring STM32F407, $(MCU)),) |
| 277 | # Cortex version | 314 | # Cortex version |
| 278 | MCU = cortex-m4 | 315 | MCU = cortex-m4 |
| @@ -504,6 +541,37 @@ ifneq (,$(filter $(MCU),STM32L412 STM32L422)) | |||
| 504 | UF2_FAMILY ?= STM32L4 | 541 | UF2_FAMILY ?= STM32L4 |
| 505 | endif | 542 | endif |
| 506 | 543 | ||
| 544 | ifneq ($(findstring GD32VF103, $(MCU)),) | ||
| 545 | # RISC-V | ||
| 546 | MCU = risc-v | ||
| 547 | |||
| 548 | # RISC-V extensions and abi configuration | ||
| 549 | MCU_ARCH = rv32imac | ||
| 550 | MCU_ABI = ilp32 | ||
| 551 | MCU_CMODEL = medlow | ||
| 552 | |||
| 553 | ## chip/board settings | ||
| 554 | # - the next two should match the directories in | ||
| 555 | # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES) | ||
| 556 | MCU_FAMILY = GD32V | ||
| 557 | MCU_SERIES = GD32VF103 | ||
| 558 | |||
| 559 | # Linker script to use | ||
| 560 | # - it should exist either in <chibios>/os/common/startup/RISCV-ECLIC/compilers/GCC/ld/ | ||
| 561 | # or <keyboard_dir>/ld/ | ||
| 562 | MCU_LDSCRIPT ?= GD32VF103xB | ||
| 563 | |||
| 564 | # Startup code to use | ||
| 565 | # - it should exist in <chibios>/os/common/startup/RISCV-ECLIC/compilers/GCC/mk/ | ||
| 566 | MCU_STARTUP ?= gd32vf103 | ||
| 567 | |||
| 568 | # Board: it should exist either in <chibios>/os/hal/boards/, | ||
| 569 | # <keyboard_dir>/boards/, or drivers/boards/ | ||
| 570 | BOARD ?= SIPEED_LONGAN_NANO | ||
| 571 | |||
| 572 | USE_FPU ?= no | ||
| 573 | endif | ||
| 574 | |||
| 507 | ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647 at90usb1286 at90usb1287)) | 575 | ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647 at90usb1286 at90usb1287)) |
| 508 | PROTOCOL = LUFA | 576 | PROTOCOL = LUFA |
| 509 | 577 | ||
diff --git a/quantum/process_keycode/process_haptic.c b/quantum/process_keycode/process_haptic.c index 64d455d00..1b9c2f24f 100644 --- a/quantum/process_keycode/process_haptic.c +++ b/quantum/process_keycode/process_haptic.c | |||
| @@ -32,6 +32,7 @@ __attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t | |||
| 32 | break; | 32 | break; |
| 33 | case KC_LCTRL ... KC_RGUI: | 33 | case KC_LCTRL ... KC_RGUI: |
| 34 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: | 34 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: |
| 35 | case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: | ||
| 35 | #endif | 36 | #endif |
| 36 | #ifdef NO_HAPTIC_FN | 37 | #ifdef NO_HAPTIC_FN |
| 37 | case KC_FN0 ... KC_FN31: | 38 | case KC_FN0 ... KC_FN31: |
diff --git a/quantum/process_keycode/process_programmable_button.c b/quantum/process_keycode/process_programmable_button.c new file mode 100644 index 000000000..c6e77faac --- /dev/null +++ b/quantum/process_keycode/process_programmable_button.c | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "process_programmable_button.h" | ||
| 19 | #include "programmable_button.h" | ||
| 20 | |||
| 21 | bool process_programmable_button(uint16_t keycode, keyrecord_t *record) { | ||
| 22 | if (keycode >= PROGRAMMABLE_BUTTON_MIN && keycode <= PROGRAMMABLE_BUTTON_MAX) { | ||
| 23 | uint8_t button = keycode - PROGRAMMABLE_BUTTON_MIN + 1; | ||
| 24 | if (record->event.pressed) { | ||
| 25 | programmable_button_on(button); | ||
| 26 | } else { | ||
| 27 | programmable_button_off(button); | ||
| 28 | } | ||
| 29 | } | ||
| 30 | return true; | ||
| 31 | } | ||
diff --git a/quantum/process_keycode/process_programmable_button.h b/quantum/process_keycode/process_programmable_button.h new file mode 100644 index 000000000..47c6ce561 --- /dev/null +++ b/quantum/process_keycode/process_programmable_button.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <stdint.h> | ||
| 21 | #include "quantum.h" | ||
| 22 | |||
| 23 | bool process_programmable_button(uint16_t keycode, keyrecord_t *record); | ||
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c index 46fcaaa86..7853c22c5 100644 --- a/quantum/process_keycode/process_unicode_common.c +++ b/quantum/process_keycode/process_unicode_common.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | unicode_config_t unicode_config; | 22 | unicode_config_t unicode_config; |
| 23 | uint8_t unicode_saved_mods; | 23 | uint8_t unicode_saved_mods; |
| 24 | bool unicode_saved_caps_lock; | 24 | bool unicode_saved_caps_lock; |
| 25 | bool unicode_saved_num_lock; | ||
| 25 | 26 | ||
| 26 | #if UNICODE_SELECTED_MODES != -1 | 27 | #if UNICODE_SELECTED_MODES != -1 |
| 27 | static uint8_t selected[] = {UNICODE_SELECTED_MODES}; | 28 | static uint8_t selected[] = {UNICODE_SELECTED_MODES}; |
| @@ -79,13 +80,14 @@ void persist_unicode_input_mode(void) { eeprom_update_byte(EECONFIG_UNICODEMODE, | |||
| 79 | 80 | ||
| 80 | __attribute__((weak)) void unicode_input_start(void) { | 81 | __attribute__((weak)) void unicode_input_start(void) { |
| 81 | unicode_saved_caps_lock = host_keyboard_led_state().caps_lock; | 82 | unicode_saved_caps_lock = host_keyboard_led_state().caps_lock; |
| 83 | unicode_saved_num_lock = host_keyboard_led_state().num_lock; | ||
| 82 | 84 | ||
| 83 | // Note the order matters here! | 85 | // Note the order matters here! |
| 84 | // Need to do this before we mess around with the mods, or else | 86 | // Need to do this before we mess around with the mods, or else |
| 85 | // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work | 87 | // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work |
| 86 | // correctly in the shifted case. | 88 | // correctly in the shifted case. |
| 87 | if (unicode_config.input_mode == UC_LNX && unicode_saved_caps_lock) { | 89 | if (unicode_config.input_mode == UC_LNX && unicode_saved_caps_lock) { |
| 88 | tap_code(KC_CAPS); | 90 | tap_code(KC_CAPSLOCK); |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | unicode_saved_mods = get_mods(); // Save current mods | 93 | unicode_saved_mods = get_mods(); // Save current mods |
| @@ -99,8 +101,12 @@ __attribute__((weak)) void unicode_input_start(void) { | |||
| 99 | tap_code16(UNICODE_KEY_LNX); | 101 | tap_code16(UNICODE_KEY_LNX); |
| 100 | break; | 102 | break; |
| 101 | case UC_WIN: | 103 | case UC_WIN: |
| 104 | // For increased reliability, use numpad keys for inputting digits | ||
| 105 | if (!unicode_saved_num_lock) { | ||
| 106 | tap_code(KC_NUMLOCK); | ||
| 107 | } | ||
| 102 | register_code(KC_LALT); | 108 | register_code(KC_LALT); |
| 103 | tap_code(KC_PPLS); | 109 | tap_code(KC_KP_PLUS); |
| 104 | break; | 110 | break; |
| 105 | case UC_WINC: | 111 | case UC_WINC: |
| 106 | tap_code(UNICODE_KEY_WINC); | 112 | tap_code(UNICODE_KEY_WINC); |
| @@ -117,13 +123,16 @@ __attribute__((weak)) void unicode_input_finish(void) { | |||
| 117 | unregister_code(UNICODE_KEY_MAC); | 123 | unregister_code(UNICODE_KEY_MAC); |
| 118 | break; | 124 | break; |
| 119 | case UC_LNX: | 125 | case UC_LNX: |
| 120 | tap_code(KC_SPC); | 126 | tap_code(KC_SPACE); |
| 121 | if (unicode_saved_caps_lock) { | 127 | if (unicode_saved_caps_lock) { |
| 122 | tap_code(KC_CAPS); | 128 | tap_code(KC_CAPSLOCK); |
| 123 | } | 129 | } |
| 124 | break; | 130 | break; |
| 125 | case UC_WIN: | 131 | case UC_WIN: |
| 126 | unregister_code(KC_LALT); | 132 | unregister_code(KC_LALT); |
| 133 | if (!unicode_saved_num_lock) { | ||
| 134 | tap_code(KC_NUMLOCK); | ||
| 135 | } | ||
| 127 | break; | 136 | break; |
| 128 | case UC_WINC: | 137 | case UC_WINC: |
| 129 | tap_code(KC_ENTER); | 138 | tap_code(KC_ENTER); |
| @@ -139,26 +148,44 @@ __attribute__((weak)) void unicode_input_cancel(void) { | |||
| 139 | unregister_code(UNICODE_KEY_MAC); | 148 | unregister_code(UNICODE_KEY_MAC); |
| 140 | break; | 149 | break; |
| 141 | case UC_LNX: | 150 | case UC_LNX: |
| 142 | tap_code(KC_ESC); | 151 | tap_code(KC_ESCAPE); |
| 143 | if (unicode_saved_caps_lock) { | 152 | if (unicode_saved_caps_lock) { |
| 144 | tap_code(KC_CAPS); | 153 | tap_code(KC_CAPSLOCK); |
| 145 | } | 154 | } |
| 146 | break; | 155 | break; |
| 147 | case UC_WINC: | 156 | case UC_WINC: |
| 148 | tap_code(KC_ESC); | 157 | tap_code(KC_ESCAPE); |
| 149 | break; | 158 | break; |
| 150 | case UC_WIN: | 159 | case UC_WIN: |
| 151 | unregister_code(KC_LALT); | 160 | unregister_code(KC_LALT); |
| 161 | if (!unicode_saved_num_lock) { | ||
| 162 | tap_code(KC_NUMLOCK); | ||
| 163 | } | ||
| 152 | break; | 164 | break; |
| 153 | } | 165 | } |
| 154 | 166 | ||
| 155 | set_mods(unicode_saved_mods); // Reregister previously set mods | 167 | set_mods(unicode_saved_mods); // Reregister previously set mods |
| 156 | } | 168 | } |
| 157 | 169 | ||
| 170 | // clang-format off | ||
| 171 | |||
| 172 | static void send_nibble_wrapper(uint8_t digit) { | ||
| 173 | if (unicode_config.input_mode == UC_WIN) { | ||
| 174 | uint8_t kc = digit < 10 | ||
| 175 | ? KC_KP_1 + (10 + digit - 1) % 10 | ||
| 176 | : KC_A + (digit - 10); | ||
| 177 | tap_code(kc); | ||
| 178 | return; | ||
| 179 | } | ||
| 180 | send_nibble(digit); | ||
| 181 | } | ||
| 182 | |||
| 183 | // clang-format on | ||
| 184 | |||
| 158 | void register_hex(uint16_t hex) { | 185 | void register_hex(uint16_t hex) { |
| 159 | for (int i = 3; i >= 0; i--) { | 186 | for (int i = 3; i >= 0; i--) { |
| 160 | uint8_t digit = ((hex >> (i * 4)) & 0xF); | 187 | uint8_t digit = ((hex >> (i * 4)) & 0xF); |
| 161 | send_nibble(digit); | 188 | send_nibble_wrapper(digit); |
| 162 | } | 189 | } |
| 163 | } | 190 | } |
| 164 | 191 | ||
| @@ -171,10 +198,10 @@ void register_hex32(uint32_t hex) { | |||
| 171 | uint8_t digit = ((hex >> (i * 4)) & 0xF); | 198 | uint8_t digit = ((hex >> (i * 4)) & 0xF); |
| 172 | if (digit == 0) { | 199 | if (digit == 0) { |
| 173 | if (!onzerostart) { | 200 | if (!onzerostart) { |
| 174 | send_nibble(digit); | 201 | send_nibble_wrapper(digit); |
| 175 | } | 202 | } |
| 176 | } else { | 203 | } else { |
| 177 | send_nibble(digit); | 204 | send_nibble_wrapper(digit); |
| 178 | onzerostart = false; | 205 | onzerostart = false; |
| 179 | } | 206 | } |
| 180 | } | 207 | } |
diff --git a/quantum/programmable_button.c b/quantum/programmable_button.c new file mode 100644 index 000000000..be828fd17 --- /dev/null +++ b/quantum/programmable_button.c | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "programmable_button.h" | ||
| 19 | #include "host.h" | ||
| 20 | |||
| 21 | #define REPORT_BIT(index) (((uint32_t)1) << (index - 1)) | ||
| 22 | |||
| 23 | static uint32_t programmable_button_report = 0; | ||
| 24 | |||
| 25 | void programmable_button_clear(void) { programmable_button_report = 0; } | ||
| 26 | |||
| 27 | void programmable_button_send(void) { host_programmable_button_send(programmable_button_report); } | ||
| 28 | |||
| 29 | void programmable_button_on(uint8_t index) { programmable_button_report |= REPORT_BIT(index); } | ||
| 30 | |||
| 31 | void programmable_button_off(uint8_t index) { programmable_button_report &= ~REPORT_BIT(index); } | ||
| 32 | |||
| 33 | bool programmable_button_is_on(uint8_t index) { return !!(programmable_button_report & REPORT_BIT(index)); }; | ||
| 34 | |||
| 35 | uint32_t programmable_button_get_report(void) { return programmable_button_report; }; | ||
| 36 | |||
| 37 | void programmable_button_set_report(uint32_t report) { programmable_button_report = report; } | ||
diff --git a/quantum/programmable_button.h b/quantum/programmable_button.h new file mode 100644 index 000000000..e89b8b9fd --- /dev/null +++ b/quantum/programmable_button.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de> | ||
| 3 | |||
| 4 | This program is free software: you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation, either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <stdint.h> | ||
| 21 | #include <stdbool.h> | ||
| 22 | #include "report.h" | ||
| 23 | |||
| 24 | void programmable_button_clear(void); | ||
| 25 | void programmable_button_send(void); | ||
| 26 | void programmable_button_on(uint8_t index); | ||
| 27 | void programmable_button_off(uint8_t index); | ||
| 28 | bool programmable_button_is_on(uint8_t index); | ||
| 29 | uint32_t programmable_button_get_report(void); | ||
| 30 | void programmable_button_set_report(uint32_t report); | ||
diff --git a/quantum/quantum.c b/quantum/quantum.c index e60378afe..ac8857df8 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -25,10 +25,6 @@ | |||
| 25 | # include "backlight.h" | 25 | # include "backlight.h" |
| 26 | #endif | 26 | #endif |
| 27 | 27 | ||
| 28 | #ifdef API_ENABLE | ||
| 29 | # include "api.h" | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #ifdef MIDI_ENABLE | 28 | #ifdef MIDI_ENABLE |
| 33 | # include "process_midi.h" | 29 | # include "process_midi.h" |
| 34 | #endif | 30 | #endif |
| @@ -145,12 +141,13 @@ void reset_keyboard(void) { | |||
| 145 | /* Convert record into usable keycode via the contained event. */ | 141 | /* Convert record into usable keycode via the contained event. */ |
| 146 | uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) { | 142 | uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) { |
| 147 | #ifdef COMBO_ENABLE | 143 | #ifdef COMBO_ENABLE |
| 148 | if (record->keycode) { return record->keycode; } | 144 | if (record->keycode) { |
| 145 | return record->keycode; | ||
| 146 | } | ||
| 149 | #endif | 147 | #endif |
| 150 | return get_event_keycode(record->event, update_layer_cache); | 148 | return get_event_keycode(record->event, update_layer_cache); |
| 151 | } | 149 | } |
| 152 | 150 | ||
| 153 | |||
| 154 | /* Convert event into usable keycode. Checks the layer cache to ensure that it | 151 | /* Convert event into usable keycode. Checks the layer cache to ensure that it |
| 155 | * retains the correct keycode after a layer change, if the key is still pressed. | 152 | * retains the correct keycode after a layer change, if the key is still pressed. |
| 156 | * "update_layer_cache" is to ensure that it only updates the layer cache when | 153 | * "update_layer_cache" is to ensure that it only updates the layer cache when |
| @@ -179,12 +176,12 @@ uint16_t get_event_keycode(keyevent_t event, bool update_layer_cache) { | |||
| 179 | bool pre_process_record_quantum(keyrecord_t *record) { | 176 | bool pre_process_record_quantum(keyrecord_t *record) { |
| 180 | if (!( | 177 | if (!( |
| 181 | #ifdef COMBO_ENABLE | 178 | #ifdef COMBO_ENABLE |
| 182 | process_combo(get_record_keycode(record, true), record) && | 179 | process_combo(get_record_keycode(record, true), record) && |
| 183 | #endif | 180 | #endif |
| 184 | true)) { | 181 | true)) { |
| 185 | return false; | 182 | return false; |
| 186 | } | 183 | } |
| 187 | return true; // continue processing | 184 | return true; // continue processing |
| 188 | } | 185 | } |
| 189 | 186 | ||
| 190 | /* Get keycode, and then call keyboard function */ | 187 | /* Get keycode, and then call keyboard function */ |
| @@ -296,6 +293,9 @@ bool process_record_quantum(keyrecord_t *record) { | |||
| 296 | #ifdef JOYSTICK_ENABLE | 293 | #ifdef JOYSTICK_ENABLE |
| 297 | process_joystick(keycode, record) && | 294 | process_joystick(keycode, record) && |
| 298 | #endif | 295 | #endif |
| 296 | #ifdef PROGRAMMABLE_BUTTON_ENABLE | ||
| 297 | process_programmable_button(keycode, record) && | ||
| 298 | #endif | ||
| 299 | true)) { | 299 | true)) { |
| 300 | return false; | 300 | return false; |
| 301 | } | 301 | } |
| @@ -465,14 +465,6 @@ void matrix_scan_quantum() { | |||
| 465 | # include "hd44780.h" | 465 | # include "hd44780.h" |
| 466 | #endif | 466 | #endif |
| 467 | 467 | ||
| 468 | void api_send_unicode(uint32_t unicode) { | ||
| 469 | #ifdef API_ENABLE | ||
| 470 | uint8_t chunk[4]; | ||
| 471 | dword_to_bytes(unicode, chunk); | ||
| 472 | MT_SEND_DATA(DT_UNICODE, chunk, 5); | ||
| 473 | #endif | ||
| 474 | } | ||
| 475 | |||
| 476 | //------------------------------------------------------------------------------ | 468 | //------------------------------------------------------------------------------ |
| 477 | // Override these functions in your keymap file to play different tunes on | 469 | // Override these functions in your keymap file to play different tunes on |
| 478 | // different events such as startup and bootloader jump | 470 | // different events such as startup and bootloader jump |
| @@ -480,3 +472,99 @@ void api_send_unicode(uint32_t unicode) { | |||
| 480 | __attribute__((weak)) void startup_user() {} | 472 | __attribute__((weak)) void startup_user() {} |
| 481 | 473 | ||
| 482 | __attribute__((weak)) void shutdown_user() {} | 474 | __attribute__((weak)) void shutdown_user() {} |
| 475 | |||
| 476 | /** \brief Run keyboard level Power down | ||
| 477 | * | ||
| 478 | * FIXME: needs doc | ||
| 479 | */ | ||
| 480 | __attribute__((weak)) void suspend_power_down_user(void) {} | ||
| 481 | /** \brief Run keyboard level Power down | ||
| 482 | * | ||
| 483 | * FIXME: needs doc | ||
| 484 | */ | ||
| 485 | __attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); } | ||
| 486 | |||
| 487 | void suspend_power_down_quantum(void) { | ||
| 488 | #ifndef NO_SUSPEND_POWER_DOWN | ||
| 489 | // Turn off backlight | ||
| 490 | # ifdef BACKLIGHT_ENABLE | ||
| 491 | backlight_set(0); | ||
| 492 | # endif | ||
| 493 | |||
| 494 | # ifdef LED_MATRIX_ENABLE | ||
| 495 | led_matrix_task(); | ||
| 496 | # endif | ||
| 497 | # ifdef RGB_MATRIX_ENABLE | ||
| 498 | rgb_matrix_task(); | ||
| 499 | # endif | ||
| 500 | |||
| 501 | // Turn off LED indicators | ||
| 502 | uint8_t leds_off = 0; | ||
| 503 | # if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE) | ||
| 504 | if (is_backlight_enabled()) { | ||
| 505 | // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off | ||
| 506 | leds_off |= (1 << USB_LED_CAPS_LOCK); | ||
| 507 | } | ||
| 508 | # endif | ||
| 509 | led_set(leds_off); | ||
| 510 | |||
| 511 | // Turn off audio | ||
| 512 | # ifdef AUDIO_ENABLE | ||
| 513 | stop_all_notes(); | ||
| 514 | # endif | ||
| 515 | |||
| 516 | // Turn off underglow | ||
| 517 | # if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | ||
| 518 | rgblight_suspend(); | ||
| 519 | # endif | ||
| 520 | |||
| 521 | # if defined(LED_MATRIX_ENABLE) | ||
| 522 | led_matrix_set_suspend_state(true); | ||
| 523 | # endif | ||
| 524 | # if defined(RGB_MATRIX_ENABLE) | ||
| 525 | rgb_matrix_set_suspend_state(true); | ||
| 526 | # endif | ||
| 527 | |||
| 528 | # ifdef OLED_ENABLE | ||
| 529 | oled_off(); | ||
| 530 | # endif | ||
| 531 | # ifdef ST7565_ENABLE | ||
| 532 | st7565_off(); | ||
| 533 | # endif | ||
| 534 | #endif | ||
| 535 | } | ||
| 536 | |||
| 537 | /** \brief run user level code immediately after wakeup | ||
| 538 | * | ||
| 539 | * FIXME: needs doc | ||
| 540 | */ | ||
| 541 | __attribute__((weak)) void suspend_wakeup_init_user(void) {} | ||
| 542 | |||
| 543 | /** \brief run keyboard level code immediately after wakeup | ||
| 544 | * | ||
| 545 | * FIXME: needs doc | ||
| 546 | */ | ||
| 547 | __attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); } | ||
| 548 | |||
| 549 | __attribute__((weak)) void suspend_wakeup_init_quantum(void) { | ||
| 550 | // Turn on backlight | ||
| 551 | #ifdef BACKLIGHT_ENABLE | ||
| 552 | backlight_init(); | ||
| 553 | #endif | ||
| 554 | |||
| 555 | // Restore LED indicators | ||
| 556 | led_set(host_keyboard_leds()); | ||
| 557 | |||
| 558 | // Wake up underglow | ||
| 559 | #if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE) | ||
| 560 | rgblight_wakeup(); | ||
| 561 | #endif | ||
| 562 | |||
| 563 | #if defined(LED_MATRIX_ENABLE) | ||
| 564 | led_matrix_set_suspend_state(false); | ||
| 565 | #endif | ||
| 566 | #if defined(RGB_MATRIX_ENABLE) | ||
| 567 | rgb_matrix_set_suspend_state(false); | ||
| 568 | #endif | ||
| 569 | suspend_wakeup_init_kb(); | ||
| 570 | } | ||
diff --git a/quantum/quantum.h b/quantum/quantum.h index 86b717e44..9250f5acc 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h | |||
| @@ -147,6 +147,10 @@ extern layer_state_t layer_state; | |||
| 147 | # include "process_joystick.h" | 147 | # include "process_joystick.h" |
| 148 | #endif | 148 | #endif |
| 149 | 149 | ||
| 150 | #ifdef PROGRAMMABLE_BUTTON_ENABLE | ||
| 151 | # include "process_programmable_button.h" | ||
| 152 | #endif | ||
| 153 | |||
| 150 | #ifdef GRAVE_ESC_ENABLE | 154 | #ifdef GRAVE_ESC_ENABLE |
| 151 | # include "process_grave_esc.h" | 155 | # include "process_grave_esc.h" |
| 152 | #endif | 156 | #endif |
| @@ -233,5 +237,3 @@ void led_set_user(uint8_t usb_led); | |||
| 233 | void led_set_kb(uint8_t usb_led); | 237 | void led_set_kb(uint8_t usb_led); |
| 234 | bool led_update_user(led_t led_state); | 238 | bool led_update_user(led_t led_state); |
| 235 | bool led_update_kb(led_t led_state); | 239 | bool led_update_kb(led_t led_state); |
| 236 | |||
| 237 | void api_send_unicode(uint32_t unicode); | ||
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index ef4b0f457..2ea81dd4c 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h | |||
| @@ -524,6 +524,40 @@ enum quantum_keycodes { | |||
| 524 | // Additional magic key | 524 | // Additional magic key |
| 525 | MAGIC_TOGGLE_GUI, | 525 | MAGIC_TOGGLE_GUI, |
| 526 | 526 | ||
| 527 | // Programmable Button | ||
| 528 | PROGRAMMABLE_BUTTON_1, | ||
| 529 | PROGRAMMABLE_BUTTON_2, | ||
| 530 | PROGRAMMABLE_BUTTON_3, | ||
| 531 | PROGRAMMABLE_BUTTON_4, | ||
| 532 | PROGRAMMABLE_BUTTON_5, | ||
| 533 | PROGRAMMABLE_BUTTON_6, | ||
| 534 | PROGRAMMABLE_BUTTON_7, | ||
| 535 | PROGRAMMABLE_BUTTON_8, | ||
| 536 | PROGRAMMABLE_BUTTON_9, | ||
| 537 | PROGRAMMABLE_BUTTON_10, | ||
| 538 | PROGRAMMABLE_BUTTON_11, | ||
| 539 | PROGRAMMABLE_BUTTON_12, | ||
| 540 | PROGRAMMABLE_BUTTON_13, | ||
| 541 | PROGRAMMABLE_BUTTON_14, | ||
| 542 | PROGRAMMABLE_BUTTON_15, | ||
| 543 | PROGRAMMABLE_BUTTON_16, | ||
| 544 | PROGRAMMABLE_BUTTON_17, | ||
| 545 | PROGRAMMABLE_BUTTON_18, | ||
| 546 | PROGRAMMABLE_BUTTON_19, | ||
| 547 | PROGRAMMABLE_BUTTON_20, | ||
| 548 | PROGRAMMABLE_BUTTON_21, | ||
| 549 | PROGRAMMABLE_BUTTON_22, | ||
| 550 | PROGRAMMABLE_BUTTON_23, | ||
| 551 | PROGRAMMABLE_BUTTON_24, | ||
| 552 | PROGRAMMABLE_BUTTON_25, | ||
| 553 | PROGRAMMABLE_BUTTON_26, | ||
| 554 | PROGRAMMABLE_BUTTON_27, | ||
| 555 | PROGRAMMABLE_BUTTON_28, | ||
| 556 | PROGRAMMABLE_BUTTON_29, | ||
| 557 | PROGRAMMABLE_BUTTON_30, | ||
| 558 | PROGRAMMABLE_BUTTON_31, | ||
| 559 | PROGRAMMABLE_BUTTON_32, | ||
| 560 | |||
| 527 | // Start of custom keycode range for keyboards and keymaps - always leave at the end | 561 | // Start of custom keycode range for keyboards and keymaps - always leave at the end |
| 528 | SAFE_RANGE | 562 | SAFE_RANGE |
| 529 | }; | 563 | }; |
| @@ -854,3 +888,39 @@ enum quantum_keycodes { | |||
| 854 | #define OS_TOGG ONESHOT_TOGGLE | 888 | #define OS_TOGG ONESHOT_TOGGLE |
| 855 | #define OS_ON ONESHOT_ENABLE | 889 | #define OS_ON ONESHOT_ENABLE |
| 856 | #define OS_OFF ONESHOT_DISABLE | 890 | #define OS_OFF ONESHOT_DISABLE |
| 891 | |||
| 892 | // Programmable Button aliases | ||
| 893 | #define PB_1 PROGRAMMABLE_BUTTON_1 | ||
| 894 | #define PB_2 PROGRAMMABLE_BUTTON_2 | ||
| 895 | #define PB_3 PROGRAMMABLE_BUTTON_3 | ||
| 896 | #define PB_4 PROGRAMMABLE_BUTTON_4 | ||
| 897 | #define PB_5 PROGRAMMABLE_BUTTON_5 | ||
| 898 | #define PB_6 PROGRAMMABLE_BUTTON_6 | ||
| 899 | #define PB_7 PROGRAMMABLE_BUTTON_7 | ||
| 900 | #define PB_8 PROGRAMMABLE_BUTTON_8 | ||
| 901 | #define PB_9 PROGRAMMABLE_BUTTON_9 | ||
| 902 | #define PB_10 PROGRAMMABLE_BUTTON_10 | ||
| 903 | #define PB_11 PROGRAMMABLE_BUTTON_11 | ||
| 904 | #define PB_12 PROGRAMMABLE_BUTTON_12 | ||
| 905 | #define PB_13 PROGRAMMABLE_BUTTON_13 | ||
| 906 | #define PB_14 PROGRAMMABLE_BUTTON_14 | ||
| 907 | #define PB_15 PROGRAMMABLE_BUTTON_15 | ||
| 908 | #define PB_16 PROGRAMMABLE_BUTTON_16 | ||
| 909 | #define PB_17 PROGRAMMABLE_BUTTON_17 | ||
| 910 | #define PB_18 PROGRAMMABLE_BUTTON_18 | ||
| 911 | #define PB_19 PROGRAMMABLE_BUTTON_19 | ||
| 912 | #define PB_20 PROGRAMMABLE_BUTTON_20 | ||
| 913 | #define PB_21 PROGRAMMABLE_BUTTON_21 | ||
| 914 | #define PB_22 PROGRAMMABLE_BUTTON_22 | ||
| 915 | #define PB_23 PROGRAMMABLE_BUTTON_23 | ||
| 916 | #define PB_24 PROGRAMMABLE_BUTTON_24 | ||
| 917 | #define PB_25 PROGRAMMABLE_BUTTON_25 | ||
| 918 | #define PB_26 PROGRAMMABLE_BUTTON_26 | ||
| 919 | #define PB_27 PROGRAMMABLE_BUTTON_27 | ||
| 920 | #define PB_28 PROGRAMMABLE_BUTTON_28 | ||
| 921 | #define PB_29 PROGRAMMABLE_BUTTON_29 | ||
| 922 | #define PB_30 PROGRAMMABLE_BUTTON_30 | ||
| 923 | #define PB_31 PROGRAMMABLE_BUTTON_31 | ||
| 924 | #define PB_32 PROGRAMMABLE_BUTTON_32 | ||
| 925 | #define PROGRAMMABLE_BUTTON_MIN PROGRAMMABLE_BUTTON_1 | ||
| 926 | #define PROGRAMMABLE_BUTTON_MAX PROGRAMMABLE_BUTTON_32 | ||
diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c index 8f00b4087..c260b6e1e 100644 --- a/quantum/rgb_matrix/rgb_matrix.c +++ b/quantum/rgb_matrix/rgb_matrix.c | |||
| @@ -31,14 +31,6 @@ const led_point_t k_rgb_matrix_center = {112, 32}; | |||
| 31 | const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER; | 31 | const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER; |
| 32 | #endif | 32 | #endif |
| 33 | 33 | ||
| 34 | // clang-format off | ||
| 35 | #ifndef RGB_MATRIX_IMMEDIATE_EEPROM | ||
| 36 | # define rgb_eeconfig_update(v) rgb_update_eeprom |= v | ||
| 37 | #else | ||
| 38 | # define rgb_eeconfig_update(v) if (v) eeconfig_update_rgb_matrix() | ||
| 39 | #endif | ||
| 40 | // clang-format on | ||
| 41 | |||
| 42 | __attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); } | 34 | __attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); } |
| 43 | 35 | ||
| 44 | // Generic effect runners | 36 | // Generic effect runners |
| @@ -128,7 +120,6 @@ last_hit_t g_last_hit_tracker; | |||
| 128 | 120 | ||
| 129 | // internals | 121 | // internals |
| 130 | static bool suspend_state = false; | 122 | static bool suspend_state = false; |
| 131 | static bool rgb_update_eeprom = false; | ||
| 132 | static uint8_t rgb_last_enable = UINT8_MAX; | 123 | static uint8_t rgb_last_enable = UINT8_MAX; |
| 133 | static uint8_t rgb_last_effect = UINT8_MAX; | 124 | static uint8_t rgb_last_effect = UINT8_MAX; |
| 134 | static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false}; | 125 | static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false}; |
| @@ -148,9 +139,9 @@ static last_hit_t last_hit_buffer; | |||
| 148 | const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT; | 139 | const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT; |
| 149 | #endif | 140 | #endif |
| 150 | 141 | ||
| 151 | void eeconfig_read_rgb_matrix(void) { eeprom_read_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config)); } | 142 | EECONFIG_DEBOUNCE_HELPER(rgb_matrix, EECONFIG_RGB_MATRIX, rgb_matrix_config); |
| 152 | 143 | ||
| 153 | void eeconfig_update_rgb_matrix(void) { eeprom_update_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config)); } | 144 | void eeconfig_update_rgb_matrix(void) { eeconfig_flush_rgb_matrix(true); } |
| 154 | 145 | ||
| 155 | void eeconfig_update_rgb_matrix_default(void) { | 146 | void eeconfig_update_rgb_matrix_default(void) { |
| 156 | dprintf("eeconfig_update_rgb_matrix_default\n"); | 147 | dprintf("eeconfig_update_rgb_matrix_default\n"); |
| @@ -159,7 +150,7 @@ void eeconfig_update_rgb_matrix_default(void) { | |||
| 159 | rgb_matrix_config.hsv = (HSV){RGB_MATRIX_STARTUP_HUE, RGB_MATRIX_STARTUP_SAT, RGB_MATRIX_STARTUP_VAL}; | 150 | rgb_matrix_config.hsv = (HSV){RGB_MATRIX_STARTUP_HUE, RGB_MATRIX_STARTUP_SAT, RGB_MATRIX_STARTUP_VAL}; |
| 160 | rgb_matrix_config.speed = RGB_MATRIX_STARTUP_SPD; | 151 | rgb_matrix_config.speed = RGB_MATRIX_STARTUP_SPD; |
| 161 | rgb_matrix_config.flags = LED_FLAG_ALL; | 152 | rgb_matrix_config.flags = LED_FLAG_ALL; |
| 162 | eeconfig_update_rgb_matrix(); | 153 | eeconfig_flush_rgb_matrix(true); |
| 163 | } | 154 | } |
| 164 | 155 | ||
| 165 | void eeconfig_debug_rgb_matrix(void) { | 156 | void eeconfig_debug_rgb_matrix(void) { |
| @@ -314,9 +305,8 @@ static void rgb_task_timers(void) { | |||
| 314 | } | 305 | } |
| 315 | 306 | ||
| 316 | static void rgb_task_sync(void) { | 307 | static void rgb_task_sync(void) { |
| 308 | eeconfig_flush_rgb_matrix(false); | ||
| 317 | // next task | 309 | // next task |
| 318 | if (rgb_update_eeprom) eeconfig_update_rgb_matrix(); | ||
| 319 | rgb_update_eeprom = false; | ||
| 320 | if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING; | 310 | if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING; |
| 321 | } | 311 | } |
| 322 | 312 | ||
| @@ -491,7 +481,7 @@ void rgb_matrix_init(void) { | |||
| 491 | eeconfig_update_rgb_matrix_default(); | 481 | eeconfig_update_rgb_matrix_default(); |
| 492 | } | 482 | } |
| 493 | 483 | ||
| 494 | eeconfig_read_rgb_matrix(); | 484 | eeconfig_init_rgb_matrix(); |
| 495 | if (!rgb_matrix_config.mode) { | 485 | if (!rgb_matrix_config.mode) { |
| 496 | dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n"); | 486 | dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n"); |
| 497 | eeconfig_update_rgb_matrix_default(); | 487 | eeconfig_update_rgb_matrix_default(); |
| @@ -514,7 +504,7 @@ bool rgb_matrix_get_suspend_state(void) { return suspend_state; } | |||
| 514 | void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) { | 504 | void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) { |
| 515 | rgb_matrix_config.enable ^= 1; | 505 | rgb_matrix_config.enable ^= 1; |
| 516 | rgb_task_state = STARTING; | 506 | rgb_task_state = STARTING; |
| 517 | rgb_eeconfig_update(write_to_eeprom); | 507 | eeconfig_flag_rgb_matrix(write_to_eeprom); |
| 518 | dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable); | 508 | dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable); |
| 519 | } | 509 | } |
| 520 | void rgb_matrix_toggle_noeeprom(void) { rgb_matrix_toggle_eeprom_helper(false); } | 510 | void rgb_matrix_toggle_noeeprom(void) { rgb_matrix_toggle_eeprom_helper(false); } |
| @@ -522,7 +512,7 @@ void rgb_matrix_toggle(void) { rgb_matrix_toggle_eeprom_helper(true); } | |||
| 522 | 512 | ||
| 523 | void rgb_matrix_enable(void) { | 513 | void rgb_matrix_enable(void) { |
| 524 | rgb_matrix_enable_noeeprom(); | 514 | rgb_matrix_enable_noeeprom(); |
| 525 | rgb_eeconfig_update(true); | 515 | eeconfig_flag_rgb_matrix(true); |
| 526 | } | 516 | } |
| 527 | 517 | ||
| 528 | void rgb_matrix_enable_noeeprom(void) { | 518 | void rgb_matrix_enable_noeeprom(void) { |
| @@ -532,7 +522,7 @@ void rgb_matrix_enable_noeeprom(void) { | |||
| 532 | 522 | ||
| 533 | void rgb_matrix_disable(void) { | 523 | void rgb_matrix_disable(void) { |
| 534 | rgb_matrix_disable_noeeprom(); | 524 | rgb_matrix_disable_noeeprom(); |
| 535 | rgb_eeconfig_update(true); | 525 | eeconfig_flag_rgb_matrix(true); |
| 536 | } | 526 | } |
| 537 | 527 | ||
| 538 | void rgb_matrix_disable_noeeprom(void) { | 528 | void rgb_matrix_disable_noeeprom(void) { |
| @@ -554,7 +544,7 @@ void rgb_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { | |||
| 554 | rgb_matrix_config.mode = mode; | 544 | rgb_matrix_config.mode = mode; |
| 555 | } | 545 | } |
| 556 | rgb_task_state = STARTING; | 546 | rgb_task_state = STARTING; |
| 557 | rgb_eeconfig_update(write_to_eeprom); | 547 | eeconfig_flag_rgb_matrix(write_to_eeprom); |
| 558 | dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.mode); | 548 | dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.mode); |
| 559 | } | 549 | } |
| 560 | void rgb_matrix_mode_noeeprom(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, false); } | 550 | void rgb_matrix_mode_noeeprom(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, false); } |
| @@ -583,7 +573,7 @@ void rgb_matrix_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, boo | |||
| 583 | rgb_matrix_config.hsv.h = hue; | 573 | rgb_matrix_config.hsv.h = hue; |
| 584 | rgb_matrix_config.hsv.s = sat; | 574 | rgb_matrix_config.hsv.s = sat; |
| 585 | rgb_matrix_config.hsv.v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val; | 575 | rgb_matrix_config.hsv.v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val; |
| 586 | rgb_eeconfig_update(write_to_eeprom); | 576 | eeconfig_flag_rgb_matrix(write_to_eeprom); |
| 587 | dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v); | 577 | dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v); |
| 588 | } | 578 | } |
| 589 | void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false); } | 579 | void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false); } |
| @@ -620,7 +610,7 @@ void rgb_matrix_decrease_val(void) { rgb_matrix_decrease_val_helper(true); } | |||
| 620 | 610 | ||
| 621 | void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { | 611 | void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { |
| 622 | rgb_matrix_config.speed = speed; | 612 | rgb_matrix_config.speed = speed; |
| 623 | rgb_eeconfig_update(write_to_eeprom); | 613 | eeconfig_flag_rgb_matrix(write_to_eeprom); |
| 624 | dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed); | 614 | dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed); |
| 625 | } | 615 | } |
| 626 | void rgb_matrix_set_speed_noeeprom(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, false); } | 616 | void rgb_matrix_set_speed_noeeprom(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, false); } |
diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.c b/quantum/rgb_matrix/rgb_matrix_drivers.c index 2cec162e2..4335088eb 100644 --- a/quantum/rgb_matrix/rgb_matrix_drivers.c +++ b/quantum/rgb_matrix/rgb_matrix_drivers.c | |||
| @@ -24,110 +24,126 @@ | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #if defined(IS31FL3731) || defined(IS31FL3733) || defined(IS31FL3737) || defined(IS31FL3741) | 26 | #if defined(IS31FL3731) || defined(IS31FL3733) || defined(IS31FL3737) || defined(IS31FL3741) |
| 27 | |||
| 28 | # include "i2c_master.h" | 27 | # include "i2c_master.h" |
| 29 | 28 | ||
| 29 | // TODO: Remove this at some later date | ||
| 30 | # if defined(DRIVER_ADDR_1) && defined(DRIVER_ADDR_2) | ||
| 31 | # if DRIVER_ADDR_1 == DRIVER_ADDR_2 | ||
| 32 | # error "Setting DRIVER_ADDR_2 == DRIVER_ADDR_1 is obsolete. If you are only using one ISSI driver, set DRIVER_COUNT to 1 and remove DRIVER_ADDR_2" | ||
| 33 | # endif | ||
| 34 | # endif | ||
| 35 | |||
| 30 | static void init(void) { | 36 | static void init(void) { |
| 31 | i2c_init(); | 37 | i2c_init(); |
| 32 | # ifdef IS31FL3731 | 38 | |
| 39 | # if defined(IS31FL3731) | ||
| 33 | IS31FL3731_init(DRIVER_ADDR_1); | 40 | IS31FL3731_init(DRIVER_ADDR_1); |
| 34 | # ifdef DRIVER_ADDR_2 | 41 | # if defined(DRIVER_ADDR_2) |
| 35 | IS31FL3731_init(DRIVER_ADDR_2); | 42 | IS31FL3731_init(DRIVER_ADDR_2); |
| 36 | # endif | 43 | # if defined(DRIVER_ADDR_3) |
| 37 | # ifdef DRIVER_ADDR_3 | ||
| 38 | IS31FL3731_init(DRIVER_ADDR_3); | 44 | IS31FL3731_init(DRIVER_ADDR_3); |
| 39 | # endif | 45 | # if defined(DRIVER_ADDR_4) |
| 40 | # ifdef DRIVER_ADDR_4 | ||
| 41 | IS31FL3731_init(DRIVER_ADDR_4); | 46 | IS31FL3731_init(DRIVER_ADDR_4); |
| 47 | # endif | ||
| 48 | # endif | ||
| 42 | # endif | 49 | # endif |
| 50 | |||
| 43 | # elif defined(IS31FL3733) | 51 | # elif defined(IS31FL3733) |
| 44 | # ifndef DRIVER_SYNC_1 | 52 | # if !defined(DRIVER_SYNC_1) |
| 45 | # define DRIVER_SYNC_1 0 | 53 | # define DRIVER_SYNC_1 0 |
| 46 | # endif | 54 | # endif |
| 47 | IS31FL3733_init(DRIVER_ADDR_1, DRIVER_SYNC_1); | 55 | IS31FL3733_init(DRIVER_ADDR_1, DRIVER_SYNC_1); |
| 48 | # if defined DRIVER_ADDR_2 && (DRIVER_ADDR_1 != DRIVER_ADDR_2) | 56 | # if defined(DRIVER_ADDR_2) |
| 49 | # ifndef DRIVER_SYNC_2 | 57 | # if !defined(DRIVER_SYNC_2) |
| 50 | # define DRIVER_SYNC_2 0 | 58 | # define DRIVER_SYNC_2 0 |
| 51 | # endif | 59 | # endif |
| 52 | IS31FL3733_init(DRIVER_ADDR_2, DRIVER_SYNC_2); | 60 | IS31FL3733_init(DRIVER_ADDR_2, DRIVER_SYNC_2); |
| 53 | # endif | 61 | # if defined(DRIVER_ADDR_3) |
| 54 | # ifdef DRIVER_ADDR_3 | 62 | # if !defined(DRIVER_SYNC_3) |
| 55 | # ifndef DRIVER_SYNC_3 | 63 | # define DRIVER_SYNC_3 0 |
| 56 | # define DRIVER_SYNC_3 0 | 64 | # endif |
| 57 | # endif | ||
| 58 | IS31FL3733_init(DRIVER_ADDR_3, DRIVER_SYNC_3); | 65 | IS31FL3733_init(DRIVER_ADDR_3, DRIVER_SYNC_3); |
| 59 | # endif | 66 | # if defined(DRIVER_ADDR_4) |
| 60 | # ifdef DRIVER_ADDR_4 | 67 | # if !defined(DRIVER_SYNC_4) |
| 61 | # ifndef DRIVER_SYNC_4 | 68 | # define DRIVER_SYNC_4 0 |
| 62 | # define DRIVER_SYNC_4 0 | 69 | # endif |
| 63 | # endif | ||
| 64 | IS31FL3733_init(DRIVER_ADDR_4, DRIVER_SYNC_4); | 70 | IS31FL3733_init(DRIVER_ADDR_4, DRIVER_SYNC_4); |
| 71 | # endif | ||
| 72 | # endif | ||
| 65 | # endif | 73 | # endif |
| 74 | |||
| 66 | # elif defined(IS31FL3737) | 75 | # elif defined(IS31FL3737) |
| 67 | IS31FL3737_init(DRIVER_ADDR_1); | 76 | IS31FL3737_init(DRIVER_ADDR_1); |
| 68 | # if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility | 77 | # if defined(DRIVER_ADDR_2) |
| 69 | IS31FL3737_init(DRIVER_ADDR_2); | 78 | IS31FL3737_init(DRIVER_ADDR_2); |
| 70 | # endif | 79 | # endif |
| 71 | # else | 80 | |
| 81 | # elif defined(IS31FL3741) | ||
| 72 | IS31FL3741_init(DRIVER_ADDR_1); | 82 | IS31FL3741_init(DRIVER_ADDR_1); |
| 73 | # endif | 83 | # endif |
| 84 | |||
| 74 | for (int index = 0; index < DRIVER_LED_TOTAL; index++) { | 85 | for (int index = 0; index < DRIVER_LED_TOTAL; index++) { |
| 75 | bool enabled = true; | 86 | bool enabled = true; |
| 87 | |||
| 76 | // This only caches it for later | 88 | // This only caches it for later |
| 77 | # ifdef IS31FL3731 | 89 | # if defined(IS31FL3731) |
| 78 | IS31FL3731_set_led_control_register(index, enabled, enabled, enabled); | 90 | IS31FL3731_set_led_control_register(index, enabled, enabled, enabled); |
| 79 | # elif defined(IS31FL3733) | 91 | # elif defined(IS31FL3733) |
| 80 | IS31FL3733_set_led_control_register(index, enabled, enabled, enabled); | 92 | IS31FL3733_set_led_control_register(index, enabled, enabled, enabled); |
| 81 | # elif defined(IS31FL3737) | 93 | # elif defined(IS31FL3737) |
| 82 | IS31FL3737_set_led_control_register(index, enabled, enabled, enabled); | 94 | IS31FL3737_set_led_control_register(index, enabled, enabled, enabled); |
| 83 | # else | 95 | # elif defined(IS31FL3741) |
| 84 | IS31FL3741_set_led_control_register(index, enabled, enabled, enabled); | 96 | IS31FL3741_set_led_control_register(index, enabled, enabled, enabled); |
| 85 | # endif | 97 | # endif |
| 86 | } | 98 | } |
| 99 | |||
| 87 | // This actually updates the LED drivers | 100 | // This actually updates the LED drivers |
| 88 | # ifdef IS31FL3731 | 101 | # if defined(IS31FL3731) |
| 89 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_1, 0); | 102 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_1, 0); |
| 90 | # ifdef DRIVER_ADDR_2 | 103 | # if defined(DRIVER_ADDR_2) |
| 91 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_2, 1); | 104 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_2, 1); |
| 92 | # endif | 105 | # if defined(DRIVER_ADDR_3) |
| 93 | # ifdef DRIVER_ADDR_3 | ||
| 94 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_3, 2); | 106 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_3, 2); |
| 95 | # endif | 107 | # if defined(DRIVER_ADDR_4) |
| 96 | # ifdef DRIVER_ADDR_4 | ||
| 97 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_4, 3); | 108 | IS31FL3731_update_led_control_registers(DRIVER_ADDR_4, 3); |
| 109 | # endif | ||
| 110 | # endif | ||
| 98 | # endif | 111 | # endif |
| 112 | |||
| 99 | # elif defined(IS31FL3733) | 113 | # elif defined(IS31FL3733) |
| 100 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_1, 0); | 114 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_1, 0); |
| 101 | # ifdef DRIVER_ADDR_2 | 115 | # if defined(DRIVER_ADDR_2) |
| 102 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_2, 1); | 116 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_2, 1); |
| 103 | # endif | 117 | # if defined(DRIVER_ADDR_3) |
| 104 | # ifdef DRIVER_ADDR_3 | ||
| 105 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_3, 2); | 118 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_3, 2); |
| 106 | # endif | 119 | # if defined(DRIVER_ADDR_4) |
| 107 | # ifdef DRIVER_ADDR_4 | ||
| 108 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_4, 3); | 120 | IS31FL3733_update_led_control_registers(DRIVER_ADDR_4, 3); |
| 121 | # endif | ||
| 122 | # endif | ||
| 109 | # endif | 123 | # endif |
| 124 | |||
| 110 | # elif defined(IS31FL3737) | 125 | # elif defined(IS31FL3737) |
| 111 | IS31FL3737_update_led_control_registers(DRIVER_ADDR_1, 0); | 126 | IS31FL3737_update_led_control_registers(DRIVER_ADDR_1, 0); |
| 112 | # if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility | 127 | # if defined(DRIVER_ADDR_2) |
| 113 | IS31FL3737_update_led_control_registers(DRIVER_ADDR_2, 1); | 128 | IS31FL3737_update_led_control_registers(DRIVER_ADDR_2, 1); |
| 114 | # endif | 129 | # endif |
| 115 | # else | 130 | |
| 131 | # elif defined(IS31FL3741) | ||
| 116 | IS31FL3741_update_led_control_registers(DRIVER_ADDR_1, 0); | 132 | IS31FL3741_update_led_control_registers(DRIVER_ADDR_1, 0); |
| 117 | # endif | 133 | # endif |
| 118 | } | 134 | } |
| 119 | 135 | ||
| 120 | # ifdef IS31FL3731 | 136 | # if defined(IS31FL3731) |
| 121 | static void flush(void) { | 137 | static void flush(void) { |
| 122 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_1, 0); | 138 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_1, 0); |
| 123 | # ifdef DRIVER_ADDR_2 | 139 | # if defined(DRIVER_ADDR_2) |
| 124 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_2, 1); | 140 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_2, 1); |
| 125 | # endif | 141 | # if defined(DRIVER_ADDR_3) |
| 126 | # ifdef DRIVER_ADDR_3 | ||
| 127 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_3, 2); | 142 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_3, 2); |
| 128 | # endif | 143 | # if defined(DRIVER_ADDR_4) |
| 129 | # ifdef DRIVER_ADDR_4 | ||
| 130 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_4, 3); | 144 | IS31FL3731_update_pwm_buffers(DRIVER_ADDR_4, 3); |
| 145 | # endif | ||
| 146 | # endif | ||
| 131 | # endif | 147 | # endif |
| 132 | } | 148 | } |
| 133 | 149 | ||
| @@ -137,17 +153,18 @@ const rgb_matrix_driver_t rgb_matrix_driver = { | |||
| 137 | .set_color = IS31FL3731_set_color, | 153 | .set_color = IS31FL3731_set_color, |
| 138 | .set_color_all = IS31FL3731_set_color_all, | 154 | .set_color_all = IS31FL3731_set_color_all, |
| 139 | }; | 155 | }; |
| 156 | |||
| 140 | # elif defined(IS31FL3733) | 157 | # elif defined(IS31FL3733) |
| 141 | static void flush(void) { | 158 | static void flush(void) { |
| 142 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_1, 0); | 159 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_1, 0); |
| 143 | # ifdef DRIVER_ADDR_2 | 160 | # if defined(DRIVER_ADDR_2) |
| 144 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_2, 1); | 161 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_2, 1); |
| 145 | # endif | 162 | # if defined(DRIVER_ADDR_3) |
| 146 | # ifdef DRIVER_ADDR_3 | ||
| 147 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_3, 2); | 163 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_3, 2); |
| 148 | # endif | 164 | # if defined(DRIVER_ADDR_4) |
| 149 | # ifdef DRIVER_ADDR_4 | ||
| 150 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_4, 3); | 165 | IS31FL3733_update_pwm_buffers(DRIVER_ADDR_4, 3); |
| 166 | # endif | ||
| 167 | # endif | ||
| 151 | # endif | 168 | # endif |
| 152 | } | 169 | } |
| 153 | 170 | ||
| @@ -157,10 +174,11 @@ const rgb_matrix_driver_t rgb_matrix_driver = { | |||
| 157 | .set_color = IS31FL3733_set_color, | 174 | .set_color = IS31FL3733_set_color, |
| 158 | .set_color_all = IS31FL3733_set_color_all, | 175 | .set_color_all = IS31FL3733_set_color_all, |
| 159 | }; | 176 | }; |
| 177 | |||
| 160 | # elif defined(IS31FL3737) | 178 | # elif defined(IS31FL3737) |
| 161 | static void flush(void) { | 179 | static void flush(void) { |
| 162 | IS31FL3737_update_pwm_buffers(DRIVER_ADDR_1, 0); | 180 | IS31FL3737_update_pwm_buffers(DRIVER_ADDR_1, 0); |
| 163 | # if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility | 181 | # if defined(DRIVER_ADDR_2) |
| 164 | IS31FL3737_update_pwm_buffers(DRIVER_ADDR_2, 1); | 182 | IS31FL3737_update_pwm_buffers(DRIVER_ADDR_2, 1); |
| 165 | # endif | 183 | # endif |
| 166 | } | 184 | } |
| @@ -171,10 +189,11 @@ const rgb_matrix_driver_t rgb_matrix_driver = { | |||
| 171 | .set_color = IS31FL3737_set_color, | 189 | .set_color = IS31FL3737_set_color, |
| 172 | .set_color_all = IS31FL3737_set_color_all, | 190 | .set_color_all = IS31FL3737_set_color_all, |
| 173 | }; | 191 | }; |
| 174 | # else | 192 | |
| 193 | # elif defined(IS31FL3741) | ||
| 175 | static void flush(void) { | 194 | static void flush(void) { |
| 176 | IS31FL3741_update_pwm_buffers(DRIVER_ADDR_1, 0); | 195 | IS31FL3741_update_pwm_buffers(DRIVER_ADDR_1, 0); |
| 177 | # if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility | 196 | # if defined(DRIVER_ADDR_2) |
| 178 | IS31FL3741_update_pwm_buffers(DRIVER_ADDR_2, 1); | 197 | IS31FL3741_update_pwm_buffers(DRIVER_ADDR_2, 1); |
| 179 | # endif | 198 | # endif |
| 180 | } | 199 | } |
| @@ -189,17 +208,19 @@ const rgb_matrix_driver_t rgb_matrix_driver = { | |||
| 189 | 208 | ||
| 190 | #elif defined(AW20216) | 209 | #elif defined(AW20216) |
| 191 | # include "spi_master.h" | 210 | # include "spi_master.h" |
| 211 | |||
| 192 | static void init(void) { | 212 | static void init(void) { |
| 193 | spi_init(); | 213 | spi_init(); |
| 214 | |||
| 194 | AW20216_init(DRIVER_1_CS, DRIVER_1_EN); | 215 | AW20216_init(DRIVER_1_CS, DRIVER_1_EN); |
| 195 | # ifdef DRIVER_2_CS | 216 | # if defined(DRIVER_2_CS) |
| 196 | AW20216_init(DRIVER_2_CS, DRIVER_2_EN); | 217 | AW20216_init(DRIVER_2_CS, DRIVER_2_EN); |
| 197 | # endif | 218 | # endif |
| 198 | } | 219 | } |
| 199 | 220 | ||
| 200 | static void flush(void) { | 221 | static void flush(void) { |
| 201 | AW20216_update_pwm_buffers(DRIVER_1_CS, 0); | 222 | AW20216_update_pwm_buffers(DRIVER_1_CS, 0); |
| 202 | # ifdef DRIVER_2_CS | 223 | # if defined(DRIVER_2_CS) |
| 203 | AW20216_update_pwm_buffers(DRIVER_2_CS, 1); | 224 | AW20216_update_pwm_buffers(DRIVER_2_CS, 1); |
| 204 | # endif | 225 | # endif |
| 205 | } | 226 | } |
diff --git a/quantum/sequencer/tests/rules.mk b/quantum/sequencer/tests/rules.mk index 76c221cf9..87a204669 100644 --- a/quantum/sequencer/tests/rules.mk +++ b/quantum/sequencer/tests/rules.mk | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | # The letter case of these variables might seem odd. However: | 1 | # The letter case of these variables might seem odd. However: |
| 2 | # - it is consistent with the serial_link example that is used as a reference in the Unit Testing article (https://docs.qmk.fm/#/unit_testing?id=adding-tests-for-new-or-existing-features) | 2 | # - it is consistent with the example that is used as a reference in the Unit Testing article (https://docs.qmk.fm/#/unit_testing?id=adding-tests-for-new-or-existing-features) |
| 3 | # - Neither `make test:sequencer` or `make test:SEQUENCER` work when using SCREAMING_SNAKE_CASE | 3 | # - Neither `make test:sequencer` or `make test:SEQUENCER` work when using SCREAMING_SNAKE_CASE |
| 4 | 4 | ||
| 5 | sequencer_DEFS := -DNO_DEBUG -DMIDI_MOCKED | 5 | sequencer_DEFS := -DNO_DEBUG -DMIDI_MOCKED |
diff --git a/quantum/serial_link/LICENSE b/quantum/serial_link/LICENSE deleted file mode 100644 index d13cc4b26..000000000 --- a/quantum/serial_link/LICENSE +++ /dev/null | |||
| @@ -1,19 +0,0 @@ | |||
| 1 | The MIT License (MIT) | ||
| 2 | |||
| 3 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 4 | of this software and associated documentation files (the "Software"), to deal | ||
| 5 | in the Software without restriction, including without limitation the rights | ||
| 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 7 | copies of the Software, and to permit persons to whom the Software is | ||
| 8 | furnished to do so, subject to the following conditions: | ||
| 9 | |||
| 10 | The above copyright notice and this permission notice shall be included in all | ||
| 11 | copies or substantial portions of the Software. | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 19 | SOFTWARE. | ||
diff --git a/quantum/serial_link/README.md b/quantum/serial_link/README.md deleted file mode 100644 index 05871dbdf..000000000 --- a/quantum/serial_link/README.md +++ /dev/null | |||
| @@ -1 +0,0 @@ | |||
| 1 | # qmk_serial_link | ||
diff --git a/quantum/serial_link/protocol/byte_stuffer.c b/quantum/serial_link/protocol/byte_stuffer.c deleted file mode 100644 index d3a91d828..000000000 --- a/quantum/serial_link/protocol/byte_stuffer.c +++ /dev/null | |||
| @@ -1,135 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 26 | #include "serial_link/protocol/frame_validator.h" | ||
| 27 | #include "serial_link/protocol/physical.h" | ||
| 28 | #include <stdbool.h> | ||
| 29 | |||
| 30 | // This implements the "Consistent overhead byte stuffing protocol" | ||
| 31 | // https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing | ||
| 32 | // http://www.stuartcheshire.org/papers/COBSforToN.pdf | ||
| 33 | |||
| 34 | typedef struct byte_stuffer_state { | ||
| 35 | uint16_t next_zero; | ||
| 36 | uint16_t data_pos; | ||
| 37 | bool long_frame; | ||
| 38 | uint8_t data[MAX_FRAME_SIZE]; | ||
| 39 | } byte_stuffer_state_t; | ||
| 40 | |||
| 41 | static byte_stuffer_state_t states[NUM_LINKS]; | ||
| 42 | |||
| 43 | void init_byte_stuffer_state(byte_stuffer_state_t* state) { | ||
| 44 | state->next_zero = 0; | ||
| 45 | state->data_pos = 0; | ||
| 46 | state->long_frame = false; | ||
| 47 | } | ||
| 48 | |||
| 49 | void init_byte_stuffer(void) { | ||
| 50 | int i; | ||
| 51 | for (i = 0; i < NUM_LINKS; i++) { | ||
| 52 | init_byte_stuffer_state(&states[i]); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data) { | ||
| 57 | byte_stuffer_state_t* state = &states[link]; | ||
| 58 | // Start of a new frame | ||
| 59 | if (state->next_zero == 0) { | ||
| 60 | state->next_zero = data; | ||
| 61 | state->long_frame = data == 0xFF; | ||
| 62 | state->data_pos = 0; | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | |||
| 66 | state->next_zero--; | ||
| 67 | if (data == 0) { | ||
| 68 | if (state->next_zero == 0) { | ||
| 69 | // The frame is completed | ||
| 70 | if (state->data_pos > 0) { | ||
| 71 | validator_recv_frame(link, state->data, state->data_pos); | ||
| 72 | } | ||
| 73 | } else { | ||
| 74 | // The frame is invalid, so reset | ||
| 75 | init_byte_stuffer_state(state); | ||
| 76 | } | ||
| 77 | } else { | ||
| 78 | if (state->data_pos == MAX_FRAME_SIZE) { | ||
| 79 | // We exceeded our maximum frame size | ||
| 80 | // therefore there's nothing else to do than reset to a new frame | ||
| 81 | state->next_zero = data; | ||
| 82 | state->long_frame = data == 0xFF; | ||
| 83 | state->data_pos = 0; | ||
| 84 | } else if (state->next_zero == 0) { | ||
| 85 | if (state->long_frame) { | ||
| 86 | // This is part of a long frame, so continue | ||
| 87 | state->next_zero = data; | ||
| 88 | state->long_frame = data == 0xFF; | ||
| 89 | } else { | ||
| 90 | // Special case for zeroes | ||
| 91 | state->next_zero = data; | ||
| 92 | state->data[state->data_pos++] = 0; | ||
| 93 | } | ||
| 94 | } else { | ||
| 95 | state->data[state->data_pos++] = data; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) { | ||
| 101 | send_data(link, &num_non_zero, 1); | ||
| 102 | if (end > start) { | ||
| 103 | send_data(link, start, end - start); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 108 | const uint8_t zero = 0; | ||
| 109 | if (size > 0) { | ||
| 110 | uint16_t num_non_zero = 1; | ||
| 111 | uint8_t* end = data + size; | ||
| 112 | uint8_t* start = data; | ||
| 113 | while (data < end) { | ||
| 114 | if (num_non_zero == 0xFF) { | ||
| 115 | // There's more data after big non-zero block | ||
| 116 | // So send it, and start a new block | ||
| 117 | send_block(link, start, data, num_non_zero); | ||
| 118 | start = data; | ||
| 119 | num_non_zero = 1; | ||
| 120 | } else { | ||
| 121 | if (*data == 0) { | ||
| 122 | // A zero encountered, so send the block | ||
| 123 | send_block(link, start, data, num_non_zero); | ||
| 124 | start = data + 1; | ||
| 125 | num_non_zero = 1; | ||
| 126 | } else { | ||
| 127 | num_non_zero++; | ||
| 128 | } | ||
| 129 | ++data; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | send_block(link, start, data, num_non_zero); | ||
| 133 | send_data(link, &zero, 1); | ||
| 134 | } | ||
| 135 | } | ||
diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h deleted file mode 100644 index 397ed3baa..000000000 --- a/quantum/serial_link/protocol/byte_stuffer.h +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <stdint.h> | ||
| 28 | |||
| 29 | #define MAX_FRAME_SIZE 1024 | ||
| 30 | #define NUM_LINKS 2 | ||
| 31 | |||
| 32 | void init_byte_stuffer(void); | ||
| 33 | void byte_stuffer_recv_byte(uint8_t link, uint8_t data); | ||
| 34 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
diff --git a/quantum/serial_link/protocol/frame_router.c b/quantum/serial_link/protocol/frame_router.c deleted file mode 100644 index 529267370..000000000 --- a/quantum/serial_link/protocol/frame_router.c +++ /dev/null | |||
| @@ -1,64 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/frame_router.h" | ||
| 26 | #include "serial_link/protocol/transport.h" | ||
| 27 | #include "serial_link/protocol/frame_validator.h" | ||
| 28 | |||
| 29 | static bool is_master; | ||
| 30 | |||
| 31 | void router_set_master(bool master) { is_master = master; } | ||
| 32 | |||
| 33 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 34 | if (is_master) { | ||
| 35 | if (link == DOWN_LINK) { | ||
| 36 | transport_recv_frame(data[size - 1], data, size - 1); | ||
| 37 | } | ||
| 38 | } else { | ||
| 39 | if (link == UP_LINK) { | ||
| 40 | if (data[size - 1] & 1) { | ||
| 41 | transport_recv_frame(0, data, size - 1); | ||
| 42 | } | ||
| 43 | data[size - 1] >>= 1; | ||
| 44 | validator_send_frame(DOWN_LINK, data, size); | ||
| 45 | } else { | ||
| 46 | data[size - 1]++; | ||
| 47 | validator_send_frame(UP_LINK, data, size); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { | ||
| 53 | if (destination == 0) { | ||
| 54 | if (!is_master) { | ||
| 55 | data[size] = 1; | ||
| 56 | validator_send_frame(UP_LINK, data, size + 1); | ||
| 57 | } | ||
| 58 | } else { | ||
| 59 | if (is_master) { | ||
| 60 | data[size] = destination; | ||
| 61 | validator_send_frame(DOWN_LINK, data, size + 1); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
diff --git a/quantum/serial_link/protocol/frame_router.h b/quantum/serial_link/protocol/frame_router.h deleted file mode 100644 index 9325fe4ee..000000000 --- a/quantum/serial_link/protocol/frame_router.h +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <stdint.h> | ||
| 28 | #include <stdbool.h> | ||
| 29 | |||
| 30 | #define UP_LINK 0 | ||
| 31 | #define DOWN_LINK 1 | ||
| 32 | |||
| 33 | void router_set_master(bool master); | ||
| 34 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
| 35 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size); | ||
diff --git a/quantum/serial_link/protocol/frame_validator.c b/quantum/serial_link/protocol/frame_validator.c deleted file mode 100644 index bc9136f70..000000000 --- a/quantum/serial_link/protocol/frame_validator.c +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/frame_validator.h" | ||
| 26 | #include "serial_link/protocol/frame_router.h" | ||
| 27 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 28 | #include <string.h> | ||
| 29 | |||
| 30 | const uint32_t poly8_lookup[256] = {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, | ||
| 31 | 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, | ||
| 32 | 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, | ||
| 33 | 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}; | ||
| 34 | |||
| 35 | static uint32_t crc32_byte(uint8_t* p, uint32_t bytelength) { | ||
| 36 | uint32_t crc = 0xffffffff; | ||
| 37 | while (bytelength-- != 0) crc = poly8_lookup[((uint8_t)crc ^ *(p++))] ^ (crc >> 8); | ||
| 38 | // return (~crc); also works | ||
| 39 | return (crc ^ 0xffffffff); | ||
| 40 | } | ||
| 41 | |||
| 42 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 43 | if (size > 4) { | ||
| 44 | uint32_t frame_crc; | ||
| 45 | memcpy(&frame_crc, data + size - 4, 4); | ||
| 46 | uint32_t expected_crc = crc32_byte(data, size - 4); | ||
| 47 | if (frame_crc == expected_crc) { | ||
| 48 | route_incoming_frame(link, data, size - 4); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 54 | uint32_t crc = crc32_byte(data, size); | ||
| 55 | memcpy(data + size, &crc, 4); | ||
| 56 | byte_stuffer_send_frame(link, data, size + 4); | ||
| 57 | } | ||
diff --git a/quantum/serial_link/protocol/frame_validator.h b/quantum/serial_link/protocol/frame_validator.h deleted file mode 100644 index 0f78768a0..000000000 --- a/quantum/serial_link/protocol/frame_validator.h +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <stdint.h> | ||
| 28 | |||
| 29 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
| 30 | // The buffer pointed to by the data needs 4 additional bytes | ||
| 31 | void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size); | ||
diff --git a/quantum/serial_link/protocol/physical.h b/quantum/serial_link/protocol/physical.h deleted file mode 100644 index 399c9d1f7..000000000 --- a/quantum/serial_link/protocol/physical.h +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | void send_data(uint8_t link, const uint8_t* data, uint16_t size); | ||
diff --git a/quantum/serial_link/protocol/transport.c b/quantum/serial_link/protocol/transport.c deleted file mode 100644 index 73b8dc62e..000000000 --- a/quantum/serial_link/protocol/transport.c +++ /dev/null | |||
| @@ -1,121 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/transport.h" | ||
| 26 | #include "serial_link/protocol/frame_router.h" | ||
| 27 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 28 | #include <string.h> | ||
| 29 | |||
| 30 | #define MAX_REMOTE_OBJECTS 16 | ||
| 31 | static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS]; | ||
| 32 | static uint32_t num_remote_objects = 0; | ||
| 33 | |||
| 34 | void reinitialize_serial_link_transport(void) { num_remote_objects = 0; } | ||
| 35 | |||
| 36 | void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) { | ||
| 37 | unsigned int i; | ||
| 38 | for (i = 0; i < _num_remote_objects; i++) { | ||
| 39 | remote_object_t* obj = _remote_objects[i]; | ||
| 40 | remote_objects[num_remote_objects++] = obj; | ||
| 41 | if (obj->object_type == MASTER_TO_ALL_SLAVES) { | ||
| 42 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; | ||
| 43 | triple_buffer_init(tb); | ||
| 44 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 45 | tb = (triple_buffer_object_t*)start; | ||
| 46 | triple_buffer_init(tb); | ||
| 47 | } else if (obj->object_type == MASTER_TO_SINGLE_SLAVE) { | ||
| 48 | uint8_t* start = obj->buffer; | ||
| 49 | unsigned int j; | ||
| 50 | for (j = 0; j < NUM_SLAVES; j++) { | ||
| 51 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 52 | triple_buffer_init(tb); | ||
| 53 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 54 | } | ||
| 55 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 56 | triple_buffer_init(tb); | ||
| 57 | } else { | ||
| 58 | uint8_t* start = obj->buffer; | ||
| 59 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 60 | triple_buffer_init(tb); | ||
| 61 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 62 | unsigned int j; | ||
| 63 | for (j = 0; j < NUM_SLAVES; j++) { | ||
| 64 | tb = (triple_buffer_object_t*)start; | ||
| 65 | triple_buffer_init(tb); | ||
| 66 | start += REMOTE_OBJECT_SIZE(obj->object_size); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { | ||
| 73 | uint8_t id = data[size - 1]; | ||
| 74 | if (id < num_remote_objects) { | ||
| 75 | remote_object_t* obj = remote_objects[id]; | ||
| 76 | if (obj->object_size == size - 1) { | ||
| 77 | uint8_t* start; | ||
| 78 | if (obj->object_type == MASTER_TO_ALL_SLAVES) { | ||
| 79 | start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 80 | } else if (obj->object_type == SLAVE_TO_MASTER) { | ||
| 81 | start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 82 | start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size); | ||
| 83 | } else { | ||
| 84 | start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 85 | } | ||
| 86 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 87 | void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb); | ||
| 88 | memcpy(ptr, data, size - 1); | ||
| 89 | triple_buffer_end_write_internal(tb); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | void update_transport(void) { | ||
| 95 | unsigned int i; | ||
| 96 | for (i = 0; i < num_remote_objects; i++) { | ||
| 97 | remote_object_t* obj = remote_objects[i]; | ||
| 98 | if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) { | ||
| 99 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; | ||
| 100 | uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); | ||
| 101 | if (ptr) { | ||
| 102 | ptr[obj->object_size] = i; | ||
| 103 | uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0; | ||
| 104 | router_send_frame(dest, ptr, obj->object_size + 1); | ||
| 105 | } | ||
| 106 | } else { | ||
| 107 | uint8_t* start = obj->buffer; | ||
| 108 | unsigned int j; | ||
| 109 | for (j = 0; j < NUM_SLAVES; j++) { | ||
| 110 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; | ||
| 111 | uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb); | ||
| 112 | if (ptr) { | ||
| 113 | ptr[obj->object_size] = i; | ||
| 114 | uint8_t dest = j + 1; | ||
| 115 | router_send_frame(dest, ptr, obj->object_size + 1); | ||
| 116 | } | ||
| 117 | start += LOCAL_OBJECT_SIZE(obj->object_size); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h deleted file mode 100644 index 3ce0c9fe4..000000000 --- a/quantum/serial_link/protocol/transport.h +++ /dev/null | |||
| @@ -1,139 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 28 | #include "serial_link/system/serial_link.h" | ||
| 29 | |||
| 30 | #define NUM_SLAVES 8 | ||
| 31 | #define LOCAL_OBJECT_EXTRA 16 | ||
| 32 | |||
| 33 | // master -> slave = 1 local(target all), 1 remote object | ||
| 34 | // slave -> master = 1 local(target 0), multiple remote objects | ||
| 35 | // master -> single slave (multiple local, target id), 1 remote object | ||
| 36 | typedef enum { | ||
| 37 | MASTER_TO_ALL_SLAVES, | ||
| 38 | MASTER_TO_SINGLE_SLAVE, | ||
| 39 | SLAVE_TO_MASTER, | ||
| 40 | } remote_object_type; | ||
| 41 | |||
| 42 | typedef struct { | ||
| 43 | remote_object_type object_type; | ||
| 44 | uint16_t object_size; | ||
| 45 | uint8_t buffer[] __attribute__((aligned(4))); | ||
| 46 | } remote_object_t; | ||
| 47 | |||
| 48 | #define REMOTE_OBJECT_SIZE(objectsize) (sizeof(triple_buffer_object_t) + objectsize * 3) | ||
| 49 | #define LOCAL_OBJECT_SIZE(objectsize) (sizeof(triple_buffer_object_t) + (objectsize + LOCAL_OBJECT_EXTRA) * 3) | ||
| 50 | |||
| 51 | #define REMOTE_OBJECT_HELPER(name, type, num_local, num_remote) \ | ||
| 52 | typedef struct { \ | ||
| 53 | remote_object_t object; \ | ||
| 54 | uint8_t buffer[num_remote * REMOTE_OBJECT_SIZE(sizeof(type)) + num_local * LOCAL_OBJECT_SIZE(sizeof(type))]; \ | ||
| 55 | } remote_object_##name##_t; | ||
| 56 | |||
| 57 | #define MASTER_TO_ALL_SLAVES_OBJECT(name, type) \ | ||
| 58 | REMOTE_OBJECT_HELPER(name, type, 1, 1) \ | ||
| 59 | remote_object_##name##_t remote_object_##name = {.object = { \ | ||
| 60 | .object_type = MASTER_TO_ALL_SLAVES, \ | ||
| 61 | .object_size = sizeof(type), \ | ||
| 62 | }}; \ | ||
| 63 | type* begin_write_##name(void) { \ | ||
| 64 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 65 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 66 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 67 | } \ | ||
| 68 | void end_write_##name(void) { \ | ||
| 69 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 70 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 71 | triple_buffer_end_write_internal(tb); \ | ||
| 72 | signal_data_written(); \ | ||
| 73 | } \ | ||
| 74 | type* read_##name(void) { \ | ||
| 75 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 76 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 77 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 78 | return (type*)triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 79 | } | ||
| 80 | |||
| 81 | #define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \ | ||
| 82 | REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \ | ||
| 83 | remote_object_##name##_t remote_object_##name = {.object = { \ | ||
| 84 | .object_type = MASTER_TO_SINGLE_SLAVE, \ | ||
| 85 | .object_size = sizeof(type), \ | ||
| 86 | }}; \ | ||
| 87 | type* begin_write_##name(uint8_t slave) { \ | ||
| 88 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 89 | uint8_t* start = obj->buffer; \ | ||
| 90 | start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 91 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 92 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 93 | } \ | ||
| 94 | void end_write_##name(uint8_t slave) { \ | ||
| 95 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 96 | uint8_t* start = obj->buffer; \ | ||
| 97 | start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 98 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 99 | triple_buffer_end_write_internal(tb); \ | ||
| 100 | signal_data_written(); \ | ||
| 101 | } \ | ||
| 102 | type* read_##name() { \ | ||
| 103 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 104 | uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 105 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 106 | return (type*)triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 107 | } | ||
| 108 | |||
| 109 | #define SLAVE_TO_MASTER_OBJECT(name, type) \ | ||
| 110 | REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \ | ||
| 111 | remote_object_##name##_t remote_object_##name = {.object = { \ | ||
| 112 | .object_type = SLAVE_TO_MASTER, \ | ||
| 113 | .object_size = sizeof(type), \ | ||
| 114 | }}; \ | ||
| 115 | type* begin_write_##name(void) { \ | ||
| 116 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 117 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 118 | return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \ | ||
| 119 | } \ | ||
| 120 | void end_write_##name(void) { \ | ||
| 121 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 122 | triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \ | ||
| 123 | triple_buffer_end_write_internal(tb); \ | ||
| 124 | signal_data_written(); \ | ||
| 125 | } \ | ||
| 126 | type* read_##name(uint8_t slave) { \ | ||
| 127 | remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ | ||
| 128 | uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); \ | ||
| 129 | start += slave * REMOTE_OBJECT_SIZE(obj->object_size); \ | ||
| 130 | triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ | ||
| 131 | return (type*)triple_buffer_read_internal(obj->object_size, tb); \ | ||
| 132 | } | ||
| 133 | |||
| 134 | #define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name | ||
| 135 | |||
| 136 | void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); | ||
| 137 | void reinitialize_serial_link_transport(void); | ||
| 138 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); | ||
| 139 | void update_transport(void); | ||
diff --git a/quantum/serial_link/protocol/triple_buffered_object.c b/quantum/serial_link/protocol/triple_buffered_object.c deleted file mode 100644 index e0c6d702a..000000000 --- a/quantum/serial_link/protocol/triple_buffered_object.c +++ /dev/null | |||
| @@ -1,77 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 26 | #include "serial_link/system/serial_link.h" | ||
| 27 | #include <stdbool.h> | ||
| 28 | #include <stddef.h> | ||
| 29 | |||
| 30 | #define GET_READ_INDEX() object->state & 3 | ||
| 31 | #define GET_WRITE_INDEX() (object->state >> 2) & 3 | ||
| 32 | #define GET_SHARED_INDEX() (object->state >> 4) & 3 | ||
| 33 | #define GET_DATA_AVAILABLE() (object->state >> 6) & 1 | ||
| 34 | |||
| 35 | #define SET_READ_INDEX(i) object->state = ((object->state & ~3) | i) | ||
| 36 | #define SET_WRITE_INDEX(i) object->state = ((object->state & ~(3 << 2)) | (i << 2)) | ||
| 37 | #define SET_SHARED_INDEX(i) object->state = ((object->state & ~(3 << 4)) | (i << 4)) | ||
| 38 | #define SET_DATA_AVAILABLE(i) object->state = ((object->state & ~(1 << 6)) | (i << 6)) | ||
| 39 | |||
| 40 | void triple_buffer_init(triple_buffer_object_t* object) { | ||
| 41 | object->state = 0; | ||
| 42 | SET_WRITE_INDEX(0); | ||
| 43 | SET_READ_INDEX(1); | ||
| 44 | SET_SHARED_INDEX(2); | ||
| 45 | SET_DATA_AVAILABLE(0); | ||
| 46 | } | ||
| 47 | |||
| 48 | void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object) { | ||
| 49 | serial_link_lock(); | ||
| 50 | if (GET_DATA_AVAILABLE()) { | ||
| 51 | uint8_t shared_index = GET_SHARED_INDEX(); | ||
| 52 | uint8_t read_index = GET_READ_INDEX(); | ||
| 53 | SET_READ_INDEX(shared_index); | ||
| 54 | SET_SHARED_INDEX(read_index); | ||
| 55 | SET_DATA_AVAILABLE(false); | ||
| 56 | serial_link_unlock(); | ||
| 57 | return object->buffer + object_size * shared_index; | ||
| 58 | } else { | ||
| 59 | serial_link_unlock(); | ||
| 60 | return NULL; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object) { | ||
| 65 | uint8_t write_index = GET_WRITE_INDEX(); | ||
| 66 | return object->buffer + object_size * write_index; | ||
| 67 | } | ||
| 68 | |||
| 69 | void triple_buffer_end_write_internal(triple_buffer_object_t* object) { | ||
| 70 | serial_link_lock(); | ||
| 71 | uint8_t shared_index = GET_SHARED_INDEX(); | ||
| 72 | uint8_t write_index = GET_WRITE_INDEX(); | ||
| 73 | SET_SHARED_INDEX(write_index); | ||
| 74 | SET_WRITE_INDEX(shared_index); | ||
| 75 | SET_DATA_AVAILABLE(true); | ||
| 76 | serial_link_unlock(); | ||
| 77 | } | ||
diff --git a/quantum/serial_link/protocol/triple_buffered_object.h b/quantum/serial_link/protocol/triple_buffered_object.h deleted file mode 100644 index 717d6d7b8..000000000 --- a/quantum/serial_link/protocol/triple_buffered_object.h +++ /dev/null | |||
| @@ -1,44 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <stdint.h> | ||
| 28 | |||
| 29 | typedef struct { | ||
| 30 | uint8_t state; | ||
| 31 | uint8_t buffer[] __attribute__((aligned(4))); | ||
| 32 | } triple_buffer_object_t; | ||
| 33 | |||
| 34 | void triple_buffer_init(triple_buffer_object_t* object); | ||
| 35 | |||
| 36 | #define triple_buffer_begin_write(object) (typeof(*object.buffer[0])*)triple_buffer_begin_write_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object) | ||
| 37 | |||
| 38 | #define triple_buffer_end_write(object) triple_buffer_end_write_internal((triple_buffer_object_t*)object) | ||
| 39 | |||
| 40 | #define triple_buffer_read(object) (typeof(*object.buffer[0])*)triple_buffer_read_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object) | ||
| 41 | |||
| 42 | void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object); | ||
| 43 | void triple_buffer_end_write_internal(triple_buffer_object_t* object); | ||
| 44 | void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object); | ||
diff --git a/quantum/serial_link/system/serial_link.c b/quantum/serial_link/system/serial_link.c deleted file mode 100644 index 6363f8ff3..000000000 --- a/quantum/serial_link/system/serial_link.c +++ /dev/null | |||
| @@ -1,250 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | #include "report.h" | ||
| 25 | #include "host_driver.h" | ||
| 26 | #include "serial_link/system/serial_link.h" | ||
| 27 | #include <hal.h> | ||
| 28 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 29 | #include "serial_link/protocol/transport.h" | ||
| 30 | #include "serial_link/protocol/frame_router.h" | ||
| 31 | #include "matrix.h" | ||
| 32 | #include "sync_timer.h" | ||
| 33 | #include <stdbool.h> | ||
| 34 | #include "print.h" | ||
| 35 | #include "config.h" | ||
| 36 | |||
| 37 | #define SYNC_TIMER_OFFSET 2 | ||
| 38 | |||
| 39 | static event_source_t new_data_event; | ||
| 40 | static bool serial_link_connected; | ||
| 41 | static bool is_master = false; | ||
| 42 | |||
| 43 | static uint8_t keyboard_leds(void); | ||
| 44 | static void send_keyboard(report_keyboard_t* report); | ||
| 45 | static void send_mouse(report_mouse_t* report); | ||
| 46 | static void send_system(uint16_t data); | ||
| 47 | static void send_consumer(uint16_t data); | ||
| 48 | |||
| 49 | host_driver_t serial_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; | ||
| 50 | |||
| 51 | // Define these in your Config.h file | ||
| 52 | #ifndef SERIAL_LINK_BAUD | ||
| 53 | # error "Serial link baud is not set" | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #ifndef SERIAL_LINK_THREAD_PRIORITY | ||
| 57 | # error "Serial link thread priority not set" | ||
| 58 | #endif | ||
| 59 | |||
| 60 | static SerialConfig config = {.sc_speed = SERIAL_LINK_BAUD}; | ||
| 61 | |||
| 62 | //#define DEBUG_LINK_ERRORS | ||
| 63 | |||
| 64 | static uint32_t read_from_serial(SerialDriver* driver, uint8_t link) { | ||
| 65 | const uint32_t buffer_size = 16; | ||
| 66 | uint8_t buffer[buffer_size]; | ||
| 67 | uint32_t bytes_read = sdAsynchronousRead(driver, buffer, buffer_size); | ||
| 68 | uint8_t* current = buffer; | ||
| 69 | uint8_t* end = current + bytes_read; | ||
| 70 | while (current < end) { | ||
| 71 | byte_stuffer_recv_byte(link, *current); | ||
| 72 | current++; | ||
| 73 | } | ||
| 74 | return bytes_read; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void print_error(char* str, eventflags_t flags, SerialDriver* driver) { | ||
| 78 | #ifdef DEBUG_LINK_ERRORS | ||
| 79 | if (flags & SD_PARITY_ERROR) { | ||
| 80 | print(str); | ||
| 81 | print(" Parity error\n"); | ||
| 82 | } | ||
| 83 | if (flags & SD_FRAMING_ERROR) { | ||
| 84 | print(str); | ||
| 85 | print(" Framing error\n"); | ||
| 86 | } | ||
| 87 | if (flags & SD_OVERRUN_ERROR) { | ||
| 88 | print(str); | ||
| 89 | uint32_t size = qSpaceI(&(driver->iqueue)); | ||
| 90 | xprintf(" Overrun error, queue size %d\n", size); | ||
| 91 | } | ||
| 92 | if (flags & SD_NOISE_ERROR) { | ||
| 93 | print(str); | ||
| 94 | print(" Noise error\n"); | ||
| 95 | } | ||
| 96 | if (flags & SD_BREAK_DETECTED) { | ||
| 97 | print(str); | ||
| 98 | print(" Break detected\n"); | ||
| 99 | } | ||
| 100 | #else | ||
| 101 | (void)str; | ||
| 102 | (void)flags; | ||
| 103 | (void)driver; | ||
| 104 | #endif | ||
| 105 | } | ||
| 106 | |||
| 107 | bool is_serial_link_master(void) { return is_master; } | ||
| 108 | |||
| 109 | // TODO: Optimize the stack size, this is probably way too big | ||
| 110 | static THD_WORKING_AREA(serialThreadStack, 1024); | ||
| 111 | static THD_FUNCTION(serialThread, arg) { | ||
| 112 | (void)arg; | ||
| 113 | event_listener_t new_data_listener; | ||
| 114 | event_listener_t sd1_listener; | ||
| 115 | event_listener_t sd2_listener; | ||
| 116 | chEvtRegister(&new_data_event, &new_data_listener, 0); | ||
| 117 | eventflags_t events = CHN_INPUT_AVAILABLE | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED; | ||
| 118 | chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1), &sd1_listener, EVENT_MASK(1), events); | ||
| 119 | chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2), &sd2_listener, EVENT_MASK(2), events); | ||
| 120 | bool need_wait = false; | ||
| 121 | while (true) { | ||
| 122 | eventflags_t flags1 = 0; | ||
| 123 | eventflags_t flags2 = 0; | ||
| 124 | if (need_wait) { | ||
| 125 | eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(1000)); | ||
| 126 | if (mask & EVENT_MASK(1)) { | ||
| 127 | flags1 = chEvtGetAndClearFlags(&sd1_listener); | ||
| 128 | print_error("DOWNLINK", flags1, &SD1); | ||
| 129 | } | ||
| 130 | if (mask & EVENT_MASK(2)) { | ||
| 131 | flags2 = chEvtGetAndClearFlags(&sd2_listener); | ||
| 132 | print_error("UPLINK", flags2, &SD2); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | // Always stay as master, even if the USB goes into sleep mode | ||
| 137 | is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE; | ||
| 138 | router_set_master(is_master); | ||
| 139 | |||
| 140 | need_wait = true; | ||
| 141 | need_wait &= read_from_serial(&SD2, UP_LINK) == 0; | ||
| 142 | need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0; | ||
| 143 | update_transport(); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 148 | if (link == DOWN_LINK) { | ||
| 149 | sdWrite(&SD1, data, size); | ||
| 150 | } else { | ||
| 151 | sdWrite(&SD2, data, size); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | static systime_t last_update = 0; | ||
| 156 | |||
| 157 | typedef struct { | ||
| 158 | matrix_row_t rows[MATRIX_ROWS]; | ||
| 159 | } matrix_object_t; | ||
| 160 | |||
| 161 | static matrix_object_t last_matrix = {}; | ||
| 162 | |||
| 163 | SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t); | ||
| 164 | MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool); | ||
| 165 | #ifndef DISABLE_SYNC_TIMER | ||
| 166 | MASTER_TO_ALL_SLAVES_OBJECT(sync_timer, uint32_t); | ||
| 167 | #endif | ||
| 168 | |||
| 169 | static remote_object_t* remote_objects[] = { | ||
| 170 | REMOTE_OBJECT(serial_link_connected), | ||
| 171 | REMOTE_OBJECT(keyboard_matrix), | ||
| 172 | #ifndef DISABLE_SYNC_TIMER | ||
| 173 | REMOTE_OBJECT(sync_timer), | ||
| 174 | #endif | ||
| 175 | }; | ||
| 176 | |||
| 177 | void init_serial_link(void) { | ||
| 178 | serial_link_connected = false; | ||
| 179 | init_serial_link_hal(); | ||
| 180 | add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*)); | ||
| 181 | init_byte_stuffer(); | ||
| 182 | sdStart(&SD1, &config); | ||
| 183 | sdStart(&SD2, &config); | ||
| 184 | chEvtObjectInit(&new_data_event); | ||
| 185 | (void)chThdCreateStatic(serialThreadStack, sizeof(serialThreadStack), SERIAL_LINK_THREAD_PRIORITY, serialThread, NULL); | ||
| 186 | } | ||
| 187 | |||
| 188 | void matrix_set_remote(matrix_row_t* rows, uint8_t index); | ||
| 189 | |||
| 190 | void serial_link_update(void) { | ||
| 191 | if (read_serial_link_connected()) { | ||
| 192 | serial_link_connected = true; | ||
| 193 | } | ||
| 194 | |||
| 195 | matrix_object_t matrix; | ||
| 196 | bool changed = false; | ||
| 197 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||
| 198 | matrix.rows[i] = matrix_get_row(i); | ||
| 199 | changed |= matrix.rows[i] != last_matrix.rows[i]; | ||
| 200 | } | ||
| 201 | |||
| 202 | systime_t current_time = chVTGetSystemTimeX(); | ||
| 203 | systime_t delta = current_time - last_update; | ||
| 204 | if (changed || delta > TIME_US2I(5000)) { | ||
| 205 | last_update = current_time; | ||
| 206 | last_matrix = matrix; | ||
| 207 | matrix_object_t* m = begin_write_keyboard_matrix(); | ||
| 208 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | ||
| 209 | m->rows[i] = matrix.rows[i]; | ||
| 210 | } | ||
| 211 | end_write_keyboard_matrix(); | ||
| 212 | |||
| 213 | *begin_write_serial_link_connected() = true; | ||
| 214 | end_write_serial_link_connected(); | ||
| 215 | |||
| 216 | #ifndef DISABLE_SYNC_TIMER | ||
| 217 | *begin_write_sync_timer() = sync_timer_read32() + SYNC_TIMER_OFFSET; | ||
| 218 | end_write_sync_timer(); | ||
| 219 | #endif | ||
| 220 | } | ||
| 221 | |||
| 222 | matrix_object_t* m = read_keyboard_matrix(0); | ||
| 223 | if (m) { | ||
| 224 | matrix_set_remote(m->rows, 0); | ||
| 225 | } | ||
| 226 | |||
| 227 | #ifndef DISABLE_SYNC_TIMER | ||
| 228 | uint32_t* t = read_sync_timer(); | ||
| 229 | if (t) { | ||
| 230 | sync_timer_update(*t); | ||
| 231 | } | ||
| 232 | #endif | ||
| 233 | } | ||
| 234 | |||
| 235 | void signal_data_written(void) { chEvtBroadcast(&new_data_event); } | ||
| 236 | |||
| 237 | bool is_serial_link_connected(void) { return serial_link_connected; } | ||
| 238 | |||
| 239 | host_driver_t* get_serial_link_driver(void) { return &serial_driver; } | ||
| 240 | |||
| 241 | // NOTE: The driver does nothing, because the master handles everything | ||
| 242 | uint8_t keyboard_leds(void) { return 0; } | ||
| 243 | |||
| 244 | void send_keyboard(report_keyboard_t* report) { (void)report; } | ||
| 245 | |||
| 246 | void send_mouse(report_mouse_t* report) { (void)report; } | ||
| 247 | |||
| 248 | void send_system(uint16_t data) { (void)data; } | ||
| 249 | |||
| 250 | void send_consumer(uint16_t data) { (void)data; } | ||
diff --git a/quantum/serial_link/system/serial_link.h b/quantum/serial_link/system/serial_link.h deleted file mode 100644 index adc1f6e93..000000000 --- a/quantum/serial_link/system/serial_link.h +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include "host_driver.h" | ||
| 28 | #include <stdbool.h> | ||
| 29 | |||
| 30 | void init_serial_link(void); | ||
| 31 | void init_serial_link_hal(void); | ||
| 32 | bool is_serial_link_connected(void); | ||
| 33 | bool is_serial_link_master(void); | ||
| 34 | host_driver_t* get_serial_link_driver(void); | ||
| 35 | void serial_link_update(void); | ||
| 36 | |||
| 37 | #if defined(PROTOCOL_CHIBIOS) | ||
| 38 | # include <ch.h> | ||
| 39 | |||
| 40 | static inline void serial_link_lock(void) { chSysLock(); } | ||
| 41 | |||
| 42 | static inline void serial_link_unlock(void) { chSysUnlock(); } | ||
| 43 | |||
| 44 | void signal_data_written(void); | ||
| 45 | |||
| 46 | #else | ||
| 47 | |||
| 48 | inline void serial_link_lock(void) {} | ||
| 49 | |||
| 50 | inline void serial_link_unlock(void) {} | ||
| 51 | |||
| 52 | void signal_data_written(void); | ||
| 53 | |||
| 54 | #endif | ||
diff --git a/quantum/serial_link/tests/Makefile b/quantum/serial_link/tests/Makefile deleted file mode 100644 index 11dd355b2..000000000 --- a/quantum/serial_link/tests/Makefile +++ /dev/null | |||
| @@ -1,61 +0,0 @@ | |||
| 1 | # The MIT License (MIT) | ||
| 2 | # | ||
| 3 | # Copyright (c) 2016 Fred Sundvik | ||
| 4 | # | ||
| 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | # of this software and associated documentation files (the "Software"), to deal | ||
| 7 | # in the Software without restriction, including without limitation the rights | ||
| 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | # copies of the Software, and to permit persons to whom the Software is | ||
| 10 | # furnished to do so, subject to the following conditions: | ||
| 11 | # | ||
| 12 | # The above copyright notice and this permission notice shall be included in all | ||
| 13 | # copies or substantial portions of the Software. | ||
| 14 | # | ||
| 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | # SOFTWARE. | ||
| 22 | |||
| 23 | CC = gcc | ||
| 24 | CFLAGS = | ||
| 25 | INCLUDES = -I. -I../../ | ||
| 26 | LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared | ||
| 27 | LDLIBS = -lcgreen | ||
| 28 | UNITOBJ = $(BUILDDIR)/serialtest/unitobj | ||
| 29 | DEPDIR = $(BUILDDIR)/serialtest/unit.d | ||
| 30 | UNITTESTS = $(BUILDDIR)/serialtest/unittests | ||
| 31 | DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td | ||
| 32 | EXT = .so | ||
| 33 | UNAME := $(shell uname) | ||
| 34 | ifneq (, $(findstring MINGW, $(UNAME))) | ||
| 35 | EXT = .dll | ||
| 36 | endif | ||
| 37 | ifneq (, $(findstring CYGWIN, $(UNAME))) | ||
| 38 | EXT = .dll | ||
| 39 | endif | ||
| 40 | |||
| 41 | SRC = $(wildcard *.c) | ||
| 42 | TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC)) | ||
| 43 | $(shell mkdir -p $(DEPDIR) >/dev/null) | ||
| 44 | |||
| 45 | test: $(TESTFILES) | ||
| 46 | @$(BUILDDIR)/cgreen/build-c/tools/cgreen-runner --color $(TESTFILES) | ||
| 47 | |||
| 48 | $(UNITTESTS)/%$(EXT): $(UNITOBJ)/%.o | ||
| 49 | @mkdir -p $(UNITTESTS) | ||
| 50 | $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) | ||
| 51 | |||
| 52 | $(UNITOBJ)/%.o : %.c | ||
| 53 | $(UNITOBJ)/%.o: %.c $(DEPDIR)/%.d | ||
| 54 | @mkdir -p $(UNITOBJ) | ||
| 55 | $(CC) $(CFLAGS) $(DEPFLAGS) $(INCLUDES) -c $< -o $@ | ||
| 56 | @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d | ||
| 57 | |||
| 58 | $(DEPDIR)/%.d: ; | ||
| 59 | .PRECIOUS: $(DEPDIR)/%.d | ||
| 60 | |||
| 61 | -include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC))) | ||
diff --git a/quantum/serial_link/tests/byte_stuffer_tests.cpp b/quantum/serial_link/tests/byte_stuffer_tests.cpp deleted file mode 100644 index 9e4e1768f..000000000 --- a/quantum/serial_link/tests/byte_stuffer_tests.cpp +++ /dev/null | |||
| @@ -1,450 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | #include <vector> | ||
| 28 | #include <algorithm> | ||
| 29 | extern "C" { | ||
| 30 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 31 | #include "serial_link/protocol/frame_validator.h" | ||
| 32 | #include "serial_link/protocol/physical.h" | ||
| 33 | } | ||
| 34 | |||
| 35 | using testing::_; | ||
| 36 | using testing::Args; | ||
| 37 | using testing::ElementsAreArray; | ||
| 38 | |||
| 39 | class ByteStuffer : public ::testing::Test { | ||
| 40 | public: | ||
| 41 | ByteStuffer() { | ||
| 42 | Instance = this; | ||
| 43 | init_byte_stuffer(); | ||
| 44 | } | ||
| 45 | |||
| 46 | ~ByteStuffer() { Instance = nullptr; } | ||
| 47 | |||
| 48 | MOCK_METHOD3(validator_recv_frame, void(uint8_t link, uint8_t* data, uint16_t size)); | ||
| 49 | |||
| 50 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { std::copy(data, data + size, std::back_inserter(sent_data)); } | ||
| 51 | std::vector<uint8_t> sent_data; | ||
| 52 | |||
| 53 | static ByteStuffer* Instance; | ||
| 54 | }; | ||
| 55 | |||
| 56 | ByteStuffer* ByteStuffer::Instance = nullptr; | ||
| 57 | |||
| 58 | extern "C" { | ||
| 59 | void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { ByteStuffer::Instance->validator_recv_frame(link, data, size); } | ||
| 60 | |||
| 61 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { ByteStuffer::Instance->send_data(link, data, size); } | ||
| 62 | } | ||
| 63 | |||
| 64 | TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { | ||
| 65 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0); | ||
| 66 | byte_stuffer_recv_byte(0, 0); | ||
| 67 | } | ||
| 68 | |||
| 69 | TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { | ||
| 70 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0); | ||
| 71 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 72 | } | ||
| 73 | |||
| 74 | TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) { | ||
| 75 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0); | ||
| 76 | byte_stuffer_recv_byte(0, 0x4A); | ||
| 77 | } | ||
| 78 | |||
| 79 | TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) { | ||
| 80 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0); | ||
| 81 | byte_stuffer_recv_byte(0, 1); | ||
| 82 | byte_stuffer_recv_byte(0, 0); | ||
| 83 | } | ||
| 84 | |||
| 85 | TEST_F(ByteStuffer, receives_single_byte_valid_frame) { | ||
| 86 | uint8_t expected[] = {0x37}; | ||
| 87 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 88 | byte_stuffer_recv_byte(0, 2); | ||
| 89 | byte_stuffer_recv_byte(0, 0x37); | ||
| 90 | byte_stuffer_recv_byte(0, 0); | ||
| 91 | } | ||
| 92 | TEST_F(ByteStuffer, receives_three_bytes_valid_frame) { | ||
| 93 | uint8_t expected[] = {0x37, 0x99, 0xFF}; | ||
| 94 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 95 | byte_stuffer_recv_byte(0, 4); | ||
| 96 | byte_stuffer_recv_byte(0, 0x37); | ||
| 97 | byte_stuffer_recv_byte(0, 0x99); | ||
| 98 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 99 | byte_stuffer_recv_byte(0, 0); | ||
| 100 | } | ||
| 101 | |||
| 102 | TEST_F(ByteStuffer, receives_single_zero_valid_frame) { | ||
| 103 | uint8_t expected[] = {0}; | ||
| 104 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 105 | byte_stuffer_recv_byte(0, 1); | ||
| 106 | byte_stuffer_recv_byte(0, 1); | ||
| 107 | byte_stuffer_recv_byte(0, 0); | ||
| 108 | } | ||
| 109 | |||
| 110 | TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) { | ||
| 111 | uint8_t expected[] = {5, 0, 3, 0}; | ||
| 112 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 113 | byte_stuffer_recv_byte(0, 2); | ||
| 114 | byte_stuffer_recv_byte(0, 5); | ||
| 115 | byte_stuffer_recv_byte(0, 2); | ||
| 116 | byte_stuffer_recv_byte(0, 3); | ||
| 117 | byte_stuffer_recv_byte(0, 1); | ||
| 118 | byte_stuffer_recv_byte(0, 0); | ||
| 119 | } | ||
| 120 | |||
| 121 | TEST_F(ByteStuffer, receives_two_valid_frames) { | ||
| 122 | uint8_t expected1[] = {5, 0}; | ||
| 123 | uint8_t expected2[] = {3}; | ||
| 124 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected1))); | ||
| 125 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected2))); | ||
| 126 | byte_stuffer_recv_byte(1, 2); | ||
| 127 | byte_stuffer_recv_byte(1, 5); | ||
| 128 | byte_stuffer_recv_byte(1, 1); | ||
| 129 | byte_stuffer_recv_byte(1, 0); | ||
| 130 | byte_stuffer_recv_byte(1, 2); | ||
| 131 | byte_stuffer_recv_byte(1, 3); | ||
| 132 | byte_stuffer_recv_byte(1, 0); | ||
| 133 | } | ||
| 134 | |||
| 135 | TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) { | ||
| 136 | uint8_t expected[] = {5, 7}; | ||
| 137 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 138 | byte_stuffer_recv_byte(1, 3); | ||
| 139 | byte_stuffer_recv_byte(1, 1); | ||
| 140 | byte_stuffer_recv_byte(1, 0); | ||
| 141 | byte_stuffer_recv_byte(1, 3); | ||
| 142 | byte_stuffer_recv_byte(1, 5); | ||
| 143 | byte_stuffer_recv_byte(1, 7); | ||
| 144 | byte_stuffer_recv_byte(1, 0); | ||
| 145 | } | ||
| 146 | |||
| 147 | TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { | ||
| 148 | uint8_t expected[] = {5, 7}; | ||
| 149 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 150 | byte_stuffer_recv_byte(0, 2); | ||
| 151 | byte_stuffer_recv_byte(0, 9); | ||
| 152 | byte_stuffer_recv_byte(0, 4); // This should have been zero | ||
| 153 | byte_stuffer_recv_byte(0, 0); | ||
| 154 | byte_stuffer_recv_byte(0, 3); | ||
| 155 | byte_stuffer_recv_byte(0, 5); | ||
| 156 | byte_stuffer_recv_byte(0, 7); | ||
| 157 | byte_stuffer_recv_byte(0, 0); | ||
| 158 | } | ||
| 159 | |||
| 160 | TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) { | ||
| 161 | uint8_t expected[254]; | ||
| 162 | int i; | ||
| 163 | for (i = 0; i < 254; i++) { | ||
| 164 | expected[i] = i + 1; | ||
| 165 | } | ||
| 166 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 167 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 168 | for (i = 0; i < 254; i++) { | ||
| 169 | byte_stuffer_recv_byte(0, i + 1); | ||
| 170 | } | ||
| 171 | byte_stuffer_recv_byte(0, 0); | ||
| 172 | } | ||
| 173 | |||
| 174 | TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) { | ||
| 175 | uint8_t expected[255]; | ||
| 176 | int i; | ||
| 177 | for (i = 0; i < 254; i++) { | ||
| 178 | expected[i] = i + 1; | ||
| 179 | } | ||
| 180 | expected[254] = 7; | ||
| 181 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 182 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 183 | for (i = 0; i < 254; i++) { | ||
| 184 | byte_stuffer_recv_byte(0, i + 1); | ||
| 185 | } | ||
| 186 | byte_stuffer_recv_byte(0, 2); | ||
| 187 | byte_stuffer_recv_byte(0, 7); | ||
| 188 | byte_stuffer_recv_byte(0, 0); | ||
| 189 | } | ||
| 190 | |||
| 191 | TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) { | ||
| 192 | uint8_t expected[255]; | ||
| 193 | int i; | ||
| 194 | for (i = 0; i < 254; i++) { | ||
| 195 | expected[i] = i + 1; | ||
| 196 | } | ||
| 197 | expected[254] = 0; | ||
| 198 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 199 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 200 | for (i = 0; i < 254; i++) { | ||
| 201 | byte_stuffer_recv_byte(0, i + 1); | ||
| 202 | } | ||
| 203 | byte_stuffer_recv_byte(0, 1); | ||
| 204 | byte_stuffer_recv_byte(0, 1); | ||
| 205 | byte_stuffer_recv_byte(0, 0); | ||
| 206 | } | ||
| 207 | |||
| 208 | TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) { | ||
| 209 | uint8_t expected[515]; | ||
| 210 | int i; | ||
| 211 | int j; | ||
| 212 | for (j = 0; j < 2; j++) { | ||
| 213 | for (i = 0; i < 254; i++) { | ||
| 214 | expected[i + 254 * j] = i + 1; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | for (i = 0; i < 7; i++) { | ||
| 218 | expected[254 * 2 + i] = i + 1; | ||
| 219 | } | ||
| 220 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 221 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 222 | for (i = 0; i < 254; i++) { | ||
| 223 | byte_stuffer_recv_byte(0, i + 1); | ||
| 224 | } | ||
| 225 | byte_stuffer_recv_byte(0, 0xFF); | ||
| 226 | for (i = 0; i < 254; i++) { | ||
| 227 | byte_stuffer_recv_byte(0, i + 1); | ||
| 228 | } | ||
| 229 | byte_stuffer_recv_byte(0, 8); | ||
| 230 | byte_stuffer_recv_byte(0, 1); | ||
| 231 | byte_stuffer_recv_byte(0, 2); | ||
| 232 | byte_stuffer_recv_byte(0, 3); | ||
| 233 | byte_stuffer_recv_byte(0, 4); | ||
| 234 | byte_stuffer_recv_byte(0, 5); | ||
| 235 | byte_stuffer_recv_byte(0, 6); | ||
| 236 | byte_stuffer_recv_byte(0, 7); | ||
| 237 | byte_stuffer_recv_byte(0, 0); | ||
| 238 | } | ||
| 239 | |||
| 240 | TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { | ||
| 241 | uint8_t expected[MAX_FRAME_SIZE] = {}; | ||
| 242 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 243 | int i; | ||
| 244 | byte_stuffer_recv_byte(0, 1); | ||
| 245 | for (i = 0; i < MAX_FRAME_SIZE; i++) { | ||
| 246 | byte_stuffer_recv_byte(0, 1); | ||
| 247 | } | ||
| 248 | byte_stuffer_recv_byte(0, 0); | ||
| 249 | } | ||
| 250 | |||
| 251 | TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { | ||
| 252 | uint8_t expected[1] = {0}; | ||
| 253 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0); | ||
| 254 | int i; | ||
| 255 | byte_stuffer_recv_byte(0, 1); | ||
| 256 | for (i = 0; i < MAX_FRAME_SIZE; i++) { | ||
| 257 | byte_stuffer_recv_byte(0, 1); | ||
| 258 | } | ||
| 259 | byte_stuffer_recv_byte(0, 1); | ||
| 260 | byte_stuffer_recv_byte(0, 0); | ||
| 261 | } | ||
| 262 | |||
| 263 | TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) { | ||
| 264 | uint8_t expected[1] = {1}; | ||
| 265 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 266 | int i; | ||
| 267 | byte_stuffer_recv_byte(0, 1); | ||
| 268 | for (i = 0; i < MAX_FRAME_SIZE; i++) { | ||
| 269 | byte_stuffer_recv_byte(0, 1); | ||
| 270 | } | ||
| 271 | byte_stuffer_recv_byte(0, 2); | ||
| 272 | byte_stuffer_recv_byte(0, 1); | ||
| 273 | byte_stuffer_recv_byte(0, 0); | ||
| 274 | } | ||
| 275 | |||
| 276 | TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) { | ||
| 277 | EXPECT_EQ(sent_data.size(), 0); | ||
| 278 | byte_stuffer_send_frame(0, NULL, 0); | ||
| 279 | } | ||
| 280 | |||
| 281 | TEST_F(ByteStuffer, send_one_byte_frame) { | ||
| 282 | uint8_t data[] = {5}; | ||
| 283 | byte_stuffer_send_frame(1, data, 1); | ||
| 284 | uint8_t expected[] = {2, 5, 0}; | ||
| 285 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 286 | } | ||
| 287 | |||
| 288 | TEST_F(ByteStuffer, sends_two_byte_frame) { | ||
| 289 | uint8_t data[] = {5, 0x77}; | ||
| 290 | byte_stuffer_send_frame(0, data, 2); | ||
| 291 | uint8_t expected[] = {3, 5, 0x77, 0}; | ||
| 292 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 293 | } | ||
| 294 | |||
| 295 | TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) { | ||
| 296 | uint8_t data[] = {0}; | ||
| 297 | byte_stuffer_send_frame(0, data, 1); | ||
| 298 | uint8_t expected[] = {1, 1, 0}; | ||
| 299 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 300 | } | ||
| 301 | |||
| 302 | TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) { | ||
| 303 | uint8_t data[] = {0, 9}; | ||
| 304 | byte_stuffer_send_frame(1, data, 2); | ||
| 305 | uint8_t expected[] = {1, 2, 9, 0}; | ||
| 306 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 307 | } | ||
| 308 | |||
| 309 | TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) { | ||
| 310 | uint8_t data[] = {9, 0}; | ||
| 311 | byte_stuffer_send_frame(1, data, 2); | ||
| 312 | uint8_t expected[] = {2, 9, 1, 0}; | ||
| 313 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 314 | } | ||
| 315 | |||
| 316 | TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) { | ||
| 317 | uint8_t data[] = {9, 0, 0x68}; | ||
| 318 | byte_stuffer_send_frame(0, data, 3); | ||
| 319 | uint8_t expected[] = {2, 9, 2, 0x68, 0}; | ||
| 320 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 321 | } | ||
| 322 | |||
| 323 | TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) { | ||
| 324 | uint8_t data[] = {0, 0x55, 0}; | ||
| 325 | byte_stuffer_send_frame(0, data, 3); | ||
| 326 | uint8_t expected[] = {1, 2, 0x55, 1, 0}; | ||
| 327 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 328 | } | ||
| 329 | |||
| 330 | TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) { | ||
| 331 | uint8_t data[] = {0, 0, 0}; | ||
| 332 | byte_stuffer_send_frame(0, data, 3); | ||
| 333 | uint8_t expected[] = {1, 1, 1, 1, 0}; | ||
| 334 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 335 | } | ||
| 336 | |||
| 337 | TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) { | ||
| 338 | uint8_t data[254]; | ||
| 339 | int i; | ||
| 340 | for (i = 0; i < 254; i++) { | ||
| 341 | data[i] = i + 1; | ||
| 342 | } | ||
| 343 | byte_stuffer_send_frame(0, data, 254); | ||
| 344 | uint8_t expected[256]; | ||
| 345 | expected[0] = 0xFF; | ||
| 346 | for (i = 1; i < 255; i++) { | ||
| 347 | expected[i] = i; | ||
| 348 | } | ||
| 349 | expected[255] = 0; | ||
| 350 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 351 | } | ||
| 352 | |||
| 353 | TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) { | ||
| 354 | uint8_t data[255]; | ||
| 355 | int i; | ||
| 356 | for (i = 0; i < 255; i++) { | ||
| 357 | data[i] = i + 1; | ||
| 358 | } | ||
| 359 | byte_stuffer_send_frame(0, data, 255); | ||
| 360 | uint8_t expected[258]; | ||
| 361 | expected[0] = 0xFF; | ||
| 362 | for (i = 1; i < 255; i++) { | ||
| 363 | expected[i] = i; | ||
| 364 | } | ||
| 365 | expected[255] = 2; | ||
| 366 | expected[256] = 255; | ||
| 367 | expected[257] = 0; | ||
| 368 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 369 | } | ||
| 370 | |||
| 371 | TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { | ||
| 372 | uint8_t data[255]; | ||
| 373 | int i; | ||
| 374 | for (i = 0; i < 254; i++) { | ||
| 375 | data[i] = i + 1; | ||
| 376 | } | ||
| 377 | data[254] = 0; | ||
| 378 | byte_stuffer_send_frame(0, data, 255); | ||
| 379 | uint8_t expected[258]; | ||
| 380 | expected[0] = 0xFF; | ||
| 381 | for (i = 1; i < 255; i++) { | ||
| 382 | expected[i] = i; | ||
| 383 | } | ||
| 384 | expected[255] = 1; | ||
| 385 | expected[256] = 1; | ||
| 386 | expected[257] = 0; | ||
| 387 | EXPECT_THAT(sent_data, ElementsAreArray(expected)); | ||
| 388 | } | ||
| 389 | |||
| 390 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) { | ||
| 391 | uint8_t original_data[] = {1, 2, 3}; | ||
| 392 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 393 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 394 | int i; | ||
| 395 | for (auto& d : sent_data) { | ||
| 396 | byte_stuffer_recv_byte(1, d); | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) { | ||
| 401 | uint8_t original_data[] = {1, 0, 3, 0, 0, 9}; | ||
| 402 | byte_stuffer_send_frame(1, original_data, sizeof(original_data)); | ||
| 403 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 404 | int i; | ||
| 405 | for (auto& d : sent_data) { | ||
| 406 | byte_stuffer_recv_byte(1, d); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) { | ||
| 411 | uint8_t original_data[254]; | ||
| 412 | int i; | ||
| 413 | for (i = 0; i < 254; i++) { | ||
| 414 | original_data[i] = i + 1; | ||
| 415 | } | ||
| 416 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 417 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 418 | for (auto& d : sent_data) { | ||
| 419 | byte_stuffer_recv_byte(1, d); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { | ||
| 424 | uint8_t original_data[256]; | ||
| 425 | int i; | ||
| 426 | for (i = 0; i < 254; i++) { | ||
| 427 | original_data[i] = i + 1; | ||
| 428 | } | ||
| 429 | original_data[254] = 22; | ||
| 430 | original_data[255] = 23; | ||
| 431 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 432 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 433 | for (auto& d : sent_data) { | ||
| 434 | byte_stuffer_recv_byte(1, d); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { | ||
| 439 | uint8_t original_data[255]; | ||
| 440 | int i; | ||
| 441 | for (i = 0; i < 254; i++) { | ||
| 442 | original_data[i] = i + 1; | ||
| 443 | } | ||
| 444 | original_data[254] = 0; | ||
| 445 | byte_stuffer_send_frame(0, original_data, sizeof(original_data)); | ||
| 446 | EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data))); | ||
| 447 | for (auto& d : sent_data) { | ||
| 448 | byte_stuffer_recv_byte(1, d); | ||
| 449 | } | ||
| 450 | } | ||
diff --git a/quantum/serial_link/tests/frame_router_tests.cpp b/quantum/serial_link/tests/frame_router_tests.cpp deleted file mode 100644 index f76dfb33d..000000000 --- a/quantum/serial_link/tests/frame_router_tests.cpp +++ /dev/null | |||
| @@ -1,204 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | #include <array> | ||
| 28 | extern "C" { | ||
| 29 | #include "serial_link/protocol/transport.h" | ||
| 30 | #include "serial_link/protocol/byte_stuffer.h" | ||
| 31 | #include "serial_link/protocol/frame_router.h" | ||
| 32 | } | ||
| 33 | |||
| 34 | using testing::_; | ||
| 35 | using testing::Args; | ||
| 36 | using testing::ElementsAreArray; | ||
| 37 | |||
| 38 | class FrameRouter : public testing::Test { | ||
| 39 | public: | ||
| 40 | FrameRouter() : current_router_buffer(nullptr) { | ||
| 41 | Instance = this; | ||
| 42 | init_byte_stuffer(); | ||
| 43 | } | ||
| 44 | |||
| 45 | ~FrameRouter() { Instance = nullptr; } | ||
| 46 | |||
| 47 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { | ||
| 48 | auto& buffer = current_router_buffer->send_buffers[link]; | ||
| 49 | std::copy(data, data + size, std::back_inserter(buffer)); | ||
| 50 | } | ||
| 51 | |||
| 52 | void receive_data(uint8_t link, uint8_t* data, uint16_t size) { | ||
| 53 | int i; | ||
| 54 | for (i = 0; i < size; i++) { | ||
| 55 | byte_stuffer_recv_byte(link, data[i]); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | void activate_router(uint8_t num) { | ||
| 60 | current_router_buffer = router_buffers + num; | ||
| 61 | router_set_master(num == 0); | ||
| 62 | } | ||
| 63 | |||
| 64 | void simulate_transport(uint8_t from, uint8_t to) { | ||
| 65 | activate_router(to); | ||
| 66 | if (from > to) { | ||
| 67 | receive_data(DOWN_LINK, router_buffers[from].send_buffers[UP_LINK].data(), router_buffers[from].send_buffers[UP_LINK].size()); | ||
| 68 | } else if (to > from) { | ||
| 69 | receive_data(UP_LINK, router_buffers[from].send_buffers[DOWN_LINK].data(), router_buffers[from].send_buffers[DOWN_LINK].size()); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | MOCK_METHOD3(transport_recv_frame, void(uint8_t from, uint8_t* data, uint16_t size)); | ||
| 74 | |||
| 75 | std::vector<uint8_t> received_data; | ||
| 76 | |||
| 77 | struct router_buffer { | ||
| 78 | std::vector<uint8_t> send_buffers[2]; | ||
| 79 | }; | ||
| 80 | |||
| 81 | router_buffer router_buffers[8]; | ||
| 82 | router_buffer* current_router_buffer; | ||
| 83 | |||
| 84 | static FrameRouter* Instance; | ||
| 85 | }; | ||
| 86 | |||
| 87 | FrameRouter* FrameRouter::Instance = nullptr; | ||
| 88 | |||
| 89 | typedef struct { | ||
| 90 | std::array<uint8_t, 4> data; | ||
| 91 | uint8_t extra[16]; | ||
| 92 | } frame_buffer_t; | ||
| 93 | |||
| 94 | extern "C" { | ||
| 95 | void send_data(uint8_t link, const uint8_t* data, uint16_t size) { FrameRouter::Instance->send_data(link, data, size); } | ||
| 96 | |||
| 97 | void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { FrameRouter::Instance->transport_recv_frame(from, data, size); } | ||
| 98 | } | ||
| 99 | |||
| 100 | TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) { | ||
| 101 | frame_buffer_t data; | ||
| 102 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 103 | activate_router(0); | ||
| 104 | router_send_frame(0xFF, (uint8_t*)&data, 4); | ||
| 105 | EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 106 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 107 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 108 | simulate_transport(0, 1); | ||
| 109 | EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 110 | EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 111 | |||
| 112 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 113 | simulate_transport(1, 2); | ||
| 114 | EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); | ||
| 115 | EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0); | ||
| 116 | } | ||
| 117 | |||
| 118 | TEST_F(FrameRouter, master_send_is_received_by_targets) { | ||
| 119 | frame_buffer_t data; | ||
| 120 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 121 | activate_router(0); | ||
| 122 | router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4); | ||
| 123 | EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 124 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 125 | |||
| 126 | simulate_transport(0, 1); | ||
| 127 | EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 128 | EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 129 | |||
| 130 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 131 | simulate_transport(1, 2); | ||
| 132 | EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); | ||
| 133 | EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0); | ||
| 134 | |||
| 135 | EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 136 | simulate_transport(2, 3); | ||
| 137 | EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0); | ||
| 138 | EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0); | ||
| 139 | } | ||
| 140 | |||
| 141 | TEST_F(FrameRouter, first_link_sends_to_master) { | ||
| 142 | frame_buffer_t data; | ||
| 143 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 144 | activate_router(1); | ||
| 145 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 146 | EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 147 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 148 | |||
| 149 | EXPECT_CALL(*this, transport_recv_frame(1, _, _)).With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 150 | simulate_transport(1, 0); | ||
| 151 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 152 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 153 | } | ||
| 154 | |||
| 155 | TEST_F(FrameRouter, second_link_sends_to_master) { | ||
| 156 | frame_buffer_t data; | ||
| 157 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 158 | activate_router(2); | ||
| 159 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 160 | EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0); | ||
| 161 | EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); | ||
| 162 | |||
| 163 | simulate_transport(2, 1); | ||
| 164 | EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 165 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 166 | |||
| 167 | EXPECT_CALL(*this, transport_recv_frame(2, _, _)).With(Args<1, 2>(ElementsAreArray(data.data))); | ||
| 168 | simulate_transport(1, 0); | ||
| 169 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 170 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 171 | } | ||
| 172 | |||
| 173 | TEST_F(FrameRouter, master_sends_to_master_does_nothing) { | ||
| 174 | frame_buffer_t data; | ||
| 175 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 176 | activate_router(0); | ||
| 177 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 178 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 179 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 180 | } | ||
| 181 | |||
| 182 | TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) { | ||
| 183 | frame_buffer_t data; | ||
| 184 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 185 | activate_router(1); | ||
| 186 | router_send_frame(2, (uint8_t*)&data, 4); | ||
| 187 | EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 188 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 189 | } | ||
| 190 | |||
| 191 | TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) { | ||
| 192 | frame_buffer_t data; | ||
| 193 | data.data = {0xAB, 0x70, 0x55, 0xBB}; | ||
| 194 | activate_router(1); | ||
| 195 | router_send_frame(0, (uint8_t*)&data, 4); | ||
| 196 | EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); | ||
| 197 | EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); | ||
| 198 | |||
| 199 | EXPECT_CALL(*this, transport_recv_frame(_, _, _)).Times(0); | ||
| 200 | activate_router(0); | ||
| 201 | receive_data(UP_LINK, router_buffers[1].send_buffers[UP_LINK].data(), router_buffers[1].send_buffers[UP_LINK].size()); | ||
| 202 | EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); | ||
| 203 | EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); | ||
| 204 | } | ||
diff --git a/quantum/serial_link/tests/frame_validator_tests.cpp b/quantum/serial_link/tests/frame_validator_tests.cpp deleted file mode 100644 index 43dc57b63..000000000 --- a/quantum/serial_link/tests/frame_validator_tests.cpp +++ /dev/null | |||
| @@ -1,100 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | extern "C" { | ||
| 28 | #include "serial_link/protocol/frame_validator.h" | ||
| 29 | } | ||
| 30 | |||
| 31 | using testing::_; | ||
| 32 | using testing::Args; | ||
| 33 | using testing::ElementsAreArray; | ||
| 34 | |||
| 35 | class FrameValidator : public testing::Test { | ||
| 36 | public: | ||
| 37 | FrameValidator() { Instance = this; } | ||
| 38 | |||
| 39 | ~FrameValidator() { Instance = nullptr; } | ||
| 40 | |||
| 41 | MOCK_METHOD3(route_incoming_frame, void(uint8_t link, uint8_t* data, uint16_t size)); | ||
| 42 | MOCK_METHOD3(byte_stuffer_send_frame, void(uint8_t link, uint8_t* data, uint16_t size)); | ||
| 43 | |||
| 44 | static FrameValidator* Instance; | ||
| 45 | }; | ||
| 46 | |||
| 47 | FrameValidator* FrameValidator::Instance = nullptr; | ||
| 48 | |||
| 49 | extern "C" { | ||
| 50 | void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { FrameValidator::Instance->route_incoming_frame(link, data, size); } | ||
| 51 | |||
| 52 | void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { FrameValidator::Instance->byte_stuffer_send_frame(link, data, size); } | ||
| 53 | } | ||
| 54 | |||
| 55 | TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) { | ||
| 56 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)).Times(0); | ||
| 57 | uint8_t data[] = {1, 2}; | ||
| 58 | validator_recv_frame(0, 0, 1); | ||
| 59 | validator_recv_frame(0, data, 2); | ||
| 60 | validator_recv_frame(0, data, 3); | ||
| 61 | validator_recv_frame(0, data, 4); | ||
| 62 | } | ||
| 63 | |||
| 64 | TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) { | ||
| 65 | uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; | ||
| 66 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(data, 1))); | ||
| 67 | validator_recv_frame(0, data, 5); | ||
| 68 | } | ||
| 69 | |||
| 70 | TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) { | ||
| 71 | uint8_t data[] = {0x44, 0, 0, 0, 0}; | ||
| 72 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)).Times(0); | ||
| 73 | validator_recv_frame(1, data, 5); | ||
| 74 | } | ||
| 75 | |||
| 76 | TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) { | ||
| 77 | uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA}; | ||
| 78 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(data, 4))); | ||
| 79 | validator_recv_frame(1, data, 8); | ||
| 80 | } | ||
| 81 | |||
| 82 | TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) { | ||
| 83 | uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; | ||
| 84 | EXPECT_CALL(*this, route_incoming_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(data, 5))); | ||
| 85 | validator_recv_frame(0, data, 9); | ||
| 86 | } | ||
| 87 | |||
| 88 | TEST_F(FrameValidator, sends_one_byte_with_correct_crc) { | ||
| 89 | uint8_t original[] = {0x44, 0, 0, 0, 0}; | ||
| 90 | uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; | ||
| 91 | EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 92 | validator_send_frame(0, original, 1); | ||
| 93 | } | ||
| 94 | |||
| 95 | TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) { | ||
| 96 | uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0}; | ||
| 97 | uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; | ||
| 98 | EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected))); | ||
| 99 | validator_send_frame(0, original, 5); | ||
| 100 | } | ||
diff --git a/quantum/serial_link/tests/rules.mk b/quantum/serial_link/tests/rules.mk deleted file mode 100644 index b81515bc5..000000000 --- a/quantum/serial_link/tests/rules.mk +++ /dev/null | |||
| @@ -1,22 +0,0 @@ | |||
| 1 | serial_link_byte_stuffer_SRC :=\ | ||
| 2 | $(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \ | ||
| 3 | $(SERIAL_PATH)/protocol/byte_stuffer.c | ||
| 4 | |||
| 5 | serial_link_frame_validator_SRC := \ | ||
| 6 | $(SERIAL_PATH)/tests/frame_validator_tests.cpp \ | ||
| 7 | $(SERIAL_PATH)/protocol/frame_validator.c | ||
| 8 | |||
| 9 | serial_link_frame_router_SRC := \ | ||
| 10 | $(SERIAL_PATH)/tests/frame_router_tests.cpp \ | ||
| 11 | $(SERIAL_PATH)/protocol/byte_stuffer.c \ | ||
| 12 | $(SERIAL_PATH)/protocol/frame_validator.c \ | ||
| 13 | $(SERIAL_PATH)/protocol/frame_router.c | ||
| 14 | |||
| 15 | serial_link_triple_buffered_object_SRC := \ | ||
| 16 | $(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \ | ||
| 17 | $(SERIAL_PATH)/protocol/triple_buffered_object.c | ||
| 18 | |||
| 19 | serial_link_transport_SRC := \ | ||
| 20 | $(SERIAL_PATH)/tests/transport_tests.cpp \ | ||
| 21 | $(SERIAL_PATH)/protocol/transport.c \ | ||
| 22 | $(SERIAL_PATH)/protocol/triple_buffered_object.c | ||
diff --git a/quantum/serial_link/tests/testlist.mk b/quantum/serial_link/tests/testlist.mk deleted file mode 100644 index c5edaf478..000000000 --- a/quantum/serial_link/tests/testlist.mk +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | TEST_LIST +=\ | ||
| 2 | serial_link_byte_stuffer\ | ||
| 3 | serial_link_frame_validator\ | ||
| 4 | serial_link_frame_router\ | ||
| 5 | serial_link_triple_buffered_object\ | ||
| 6 | serial_link_transport | ||
diff --git a/quantum/serial_link/tests/transport_tests.cpp b/quantum/serial_link/tests/transport_tests.cpp deleted file mode 100644 index cfd111046..000000000 --- a/quantum/serial_link/tests/transport_tests.cpp +++ /dev/null | |||
| @@ -1,184 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "gtest/gtest.h" | ||
| 26 | #include "gmock/gmock.h" | ||
| 27 | |||
| 28 | using testing::_; | ||
| 29 | using testing::Args; | ||
| 30 | using testing::ElementsAreArray; | ||
| 31 | |||
| 32 | extern "C" { | ||
| 33 | #include "serial_link/protocol/transport.h" | ||
| 34 | } | ||
| 35 | |||
| 36 | struct test_object1 { | ||
| 37 | uint32_t test; | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct test_object2 { | ||
| 41 | uint32_t test1; | ||
| 42 | uint32_t test2; | ||
| 43 | }; | ||
| 44 | |||
| 45 | MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1); | ||
| 46 | MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1); | ||
| 47 | SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1); | ||
| 48 | |||
| 49 | static remote_object_t* test_remote_objects[] = { | ||
| 50 | REMOTE_OBJECT(master_to_slave), | ||
| 51 | REMOTE_OBJECT(master_to_single_slave), | ||
| 52 | REMOTE_OBJECT(slave_to_master), | ||
| 53 | }; | ||
| 54 | |||
| 55 | class Transport : public testing::Test { | ||
| 56 | public: | ||
| 57 | Transport() { | ||
| 58 | Instance = this; | ||
| 59 | add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); | ||
| 60 | } | ||
| 61 | |||
| 62 | ~Transport() { | ||
| 63 | Instance = nullptr; | ||
| 64 | reinitialize_serial_link_transport(); | ||
| 65 | } | ||
| 66 | |||
| 67 | MOCK_METHOD0(signal_data_written, void()); | ||
| 68 | MOCK_METHOD1(router_send_frame, void(uint8_t destination)); | ||
| 69 | |||
| 70 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { | ||
| 71 | router_send_frame(destination); | ||
| 72 | std::copy(data, data + size, std::back_inserter(sent_data)); | ||
| 73 | } | ||
| 74 | |||
| 75 | static Transport* Instance; | ||
| 76 | |||
| 77 | std::vector<uint8_t> sent_data; | ||
| 78 | }; | ||
| 79 | |||
| 80 | Transport* Transport::Instance = nullptr; | ||
| 81 | |||
| 82 | extern "C" { | ||
| 83 | void signal_data_written(void) { Transport::Instance->signal_data_written(); } | ||
| 84 | |||
| 85 | void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { Transport::Instance->router_send_frame(destination, data, size); } | ||
| 86 | } | ||
| 87 | |||
| 88 | TEST_F(Transport, write_to_local_signals_an_event) { | ||
| 89 | begin_write_master_to_slave(); | ||
| 90 | EXPECT_CALL(*this, signal_data_written()); | ||
| 91 | end_write_master_to_slave(); | ||
| 92 | begin_write_slave_to_master(); | ||
| 93 | EXPECT_CALL(*this, signal_data_written()); | ||
| 94 | end_write_slave_to_master(); | ||
| 95 | begin_write_master_to_single_slave(1); | ||
| 96 | EXPECT_CALL(*this, signal_data_written()); | ||
| 97 | end_write_master_to_single_slave(1); | ||
| 98 | } | ||
| 99 | |||
| 100 | TEST_F(Transport, writes_from_master_to_all_slaves) { | ||
| 101 | update_transport(); | ||
| 102 | test_object1* obj = begin_write_master_to_slave(); | ||
| 103 | obj->test = 5; | ||
| 104 | EXPECT_CALL(*this, signal_data_written()); | ||
| 105 | end_write_master_to_slave(); | ||
| 106 | EXPECT_CALL(*this, router_send_frame(0xFF)); | ||
| 107 | update_transport(); | ||
| 108 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 109 | test_object1* obj2 = read_master_to_slave(); | ||
| 110 | EXPECT_NE(obj2, nullptr); | ||
| 111 | EXPECT_EQ(obj2->test, 5); | ||
| 112 | } | ||
| 113 | |||
| 114 | TEST_F(Transport, writes_from_slave_to_master) { | ||
| 115 | update_transport(); | ||
| 116 | test_object1* obj = begin_write_slave_to_master(); | ||
| 117 | obj->test = 7; | ||
| 118 | EXPECT_CALL(*this, signal_data_written()); | ||
| 119 | end_write_slave_to_master(); | ||
| 120 | EXPECT_CALL(*this, router_send_frame(0)); | ||
| 121 | update_transport(); | ||
| 122 | transport_recv_frame(3, sent_data.data(), sent_data.size()); | ||
| 123 | test_object1* obj2 = read_slave_to_master(2); | ||
| 124 | EXPECT_EQ(read_slave_to_master(0), nullptr); | ||
| 125 | EXPECT_NE(obj2, nullptr); | ||
| 126 | EXPECT_EQ(obj2->test, 7); | ||
| 127 | } | ||
| 128 | |||
| 129 | TEST_F(Transport, writes_from_master_to_single_slave) { | ||
| 130 | update_transport(); | ||
| 131 | test_object1* obj = begin_write_master_to_single_slave(3); | ||
| 132 | obj->test = 7; | ||
| 133 | EXPECT_CALL(*this, signal_data_written()); | ||
| 134 | end_write_master_to_single_slave(3); | ||
| 135 | EXPECT_CALL(*this, router_send_frame(4)); | ||
| 136 | update_transport(); | ||
| 137 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 138 | test_object1* obj2 = read_master_to_single_slave(); | ||
| 139 | EXPECT_NE(obj2, nullptr); | ||
| 140 | EXPECT_EQ(obj2->test, 7); | ||
| 141 | } | ||
| 142 | |||
| 143 | TEST_F(Transport, ignores_object_with_invalid_id) { | ||
| 144 | update_transport(); | ||
| 145 | test_object1* obj = begin_write_master_to_single_slave(3); | ||
| 146 | obj->test = 7; | ||
| 147 | EXPECT_CALL(*this, signal_data_written()); | ||
| 148 | end_write_master_to_single_slave(3); | ||
| 149 | EXPECT_CALL(*this, router_send_frame(4)); | ||
| 150 | update_transport(); | ||
| 151 | sent_data[sent_data.size() - 1] = 44; | ||
| 152 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 153 | test_object1* obj2 = read_master_to_single_slave(); | ||
| 154 | EXPECT_EQ(obj2, nullptr); | ||
| 155 | } | ||
| 156 | |||
| 157 | TEST_F(Transport, ignores_object_with_size_too_small) { | ||
| 158 | update_transport(); | ||
| 159 | test_object1* obj = begin_write_master_to_slave(); | ||
| 160 | obj->test = 7; | ||
| 161 | EXPECT_CALL(*this, signal_data_written()); | ||
| 162 | end_write_master_to_slave(); | ||
| 163 | EXPECT_CALL(*this, router_send_frame(_)); | ||
| 164 | update_transport(); | ||
| 165 | sent_data[sent_data.size() - 2] = 0; | ||
| 166 | transport_recv_frame(0, sent_data.data(), sent_data.size() - 1); | ||
| 167 | test_object1* obj2 = read_master_to_slave(); | ||
| 168 | EXPECT_EQ(obj2, nullptr); | ||
| 169 | } | ||
| 170 | |||
| 171 | TEST_F(Transport, ignores_object_with_size_too_big) { | ||
| 172 | update_transport(); | ||
| 173 | test_object1* obj = begin_write_master_to_slave(); | ||
| 174 | obj->test = 7; | ||
| 175 | EXPECT_CALL(*this, signal_data_written()); | ||
| 176 | end_write_master_to_slave(); | ||
| 177 | EXPECT_CALL(*this, router_send_frame(_)); | ||
| 178 | update_transport(); | ||
| 179 | sent_data.resize(sent_data.size() + 22); | ||
| 180 | sent_data[sent_data.size() - 1] = 0; | ||
| 181 | transport_recv_frame(0, sent_data.data(), sent_data.size()); | ||
| 182 | test_object1* obj2 = read_master_to_slave(); | ||
| 183 | EXPECT_EQ(obj2, nullptr); | ||
| 184 | } | ||
diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.cpp b/quantum/serial_link/tests/triple_buffered_object_tests.cpp deleted file mode 100644 index 8de9bfdeb..000000000 --- a/quantum/serial_link/tests/triple_buffered_object_tests.cpp +++ /dev/null | |||
| @@ -1,80 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "gtest/gtest.h" | ||
| 26 | extern "C" { | ||
| 27 | #include "serial_link/protocol/triple_buffered_object.h" | ||
| 28 | } | ||
| 29 | |||
| 30 | struct test_object { | ||
| 31 | uint8_t state; | ||
| 32 | uint32_t buffer[3]; | ||
| 33 | }; | ||
| 34 | |||
| 35 | test_object test_object; | ||
| 36 | |||
| 37 | class TripleBufferedObject : public testing::Test { | ||
| 38 | public: | ||
| 39 | TripleBufferedObject() { triple_buffer_init((triple_buffer_object_t*)&test_object); } | ||
| 40 | }; | ||
| 41 | |||
| 42 | TEST_F(TripleBufferedObject, writes_and_reads_object) { | ||
| 43 | *triple_buffer_begin_write(&test_object) = 0x3456ABCC; | ||
| 44 | triple_buffer_end_write(&test_object); | ||
| 45 | EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC); | ||
| 46 | } | ||
| 47 | |||
| 48 | TEST_F(TripleBufferedObject, does_not_read_empty) { EXPECT_EQ(triple_buffer_read(&test_object), nullptr); } | ||
| 49 | |||
| 50 | TEST_F(TripleBufferedObject, writes_twice_and_reads_object) { | ||
| 51 | *triple_buffer_begin_write(&test_object) = 0x3456ABCC; | ||
| 52 | triple_buffer_end_write(&test_object); | ||
| 53 | *triple_buffer_begin_write(&test_object) = 0x44778899; | ||
| 54 | triple_buffer_end_write(&test_object); | ||
| 55 | EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899); | ||
| 56 | } | ||
| 57 | |||
| 58 | TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) { | ||
| 59 | *triple_buffer_begin_write(&test_object) = 1; | ||
| 60 | triple_buffer_end_write(&test_object); | ||
| 61 | uint32_t* read = triple_buffer_read(&test_object); | ||
| 62 | *triple_buffer_begin_write(&test_object) = 2; | ||
| 63 | triple_buffer_end_write(&test_object); | ||
| 64 | EXPECT_EQ(*read, 1); | ||
| 65 | EXPECT_EQ(*triple_buffer_read(&test_object), 2); | ||
| 66 | EXPECT_EQ(triple_buffer_read(&test_object), nullptr); | ||
| 67 | } | ||
| 68 | |||
| 69 | TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { | ||
| 70 | *triple_buffer_begin_write(&test_object) = 1; | ||
| 71 | triple_buffer_end_write(&test_object); | ||
| 72 | uint32_t* read = triple_buffer_read(&test_object); | ||
| 73 | *triple_buffer_begin_write(&test_object) = 2; | ||
| 74 | triple_buffer_end_write(&test_object); | ||
| 75 | *triple_buffer_begin_write(&test_object) = 3; | ||
| 76 | triple_buffer_end_write(&test_object); | ||
| 77 | EXPECT_EQ(*read, 1); | ||
| 78 | EXPECT_EQ(*triple_buffer_read(&test_object), 3); | ||
| 79 | EXPECT_EQ(triple_buffer_read(&test_object), nullptr); | ||
| 80 | } | ||
diff --git a/quantum/usb_device_state.c b/quantum/usb_device_state.c new file mode 100644 index 000000000..5ccd309ec --- /dev/null +++ b/quantum/usb_device_state.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2021 Andrei Purdea <andrei@purdea.ro> | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "usb_device_state.h" | ||
| 19 | |||
| 20 | enum usb_device_state usb_device_state = USB_DEVICE_STATE_NO_INIT; | ||
| 21 | |||
| 22 | __attribute__((weak)) void notify_usb_device_state_change_kb(enum usb_device_state usb_device_state) { notify_usb_device_state_change_user(usb_device_state); } | ||
| 23 | |||
| 24 | __attribute__((weak)) void notify_usb_device_state_change_user(enum usb_device_state usb_device_state) {} | ||
| 25 | |||
| 26 | static void notify_usb_device_state_change(enum usb_device_state usb_device_state) { notify_usb_device_state_change_kb(usb_device_state); } | ||
| 27 | |||
| 28 | void usb_device_state_set_configuration(bool isConfigured, uint8_t configurationNumber) { | ||
| 29 | usb_device_state = isConfigured ? USB_DEVICE_STATE_CONFIGURED : USB_DEVICE_STATE_INIT; | ||
| 30 | notify_usb_device_state_change(usb_device_state); | ||
| 31 | } | ||
| 32 | |||
| 33 | void usb_device_state_set_suspend(bool isConfigured, uint8_t configurationNumber) { | ||
| 34 | usb_device_state = USB_DEVICE_STATE_SUSPEND; | ||
| 35 | notify_usb_device_state_change(usb_device_state); | ||
| 36 | } | ||
| 37 | |||
| 38 | void usb_device_state_set_resume(bool isConfigured, uint8_t configurationNumber) { | ||
| 39 | usb_device_state = isConfigured ? USB_DEVICE_STATE_CONFIGURED : USB_DEVICE_STATE_INIT; | ||
| 40 | notify_usb_device_state_change(usb_device_state); | ||
| 41 | } | ||
| 42 | |||
| 43 | void usb_device_state_set_reset(void) { | ||
| 44 | usb_device_state = USB_DEVICE_STATE_INIT; | ||
| 45 | notify_usb_device_state_change(usb_device_state); | ||
| 46 | } | ||
| 47 | |||
| 48 | void usb_device_state_init(void) { | ||
| 49 | usb_device_state = USB_DEVICE_STATE_INIT; | ||
| 50 | notify_usb_device_state_change(usb_device_state); | ||
| 51 | } | ||
diff --git a/quantum/usb_device_state.h b/quantum/usb_device_state.h new file mode 100644 index 000000000..c229311d4 --- /dev/null +++ b/quantum/usb_device_state.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2021 Andrei Purdea <andrei@purdea.ro> | ||
| 3 | * | ||
| 4 | * This program is free software: you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation, either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <stdbool.h> | ||
| 21 | #include <stdint.h> | ||
| 22 | |||
| 23 | void usb_device_state_set_configuration(bool isConfigured, uint8_t configurationNumber); | ||
| 24 | void usb_device_state_set_suspend(bool isConfigured, uint8_t configurationNumber); | ||
| 25 | void usb_device_state_set_resume(bool isConfigured, uint8_t configurationNumber); | ||
| 26 | void usb_device_state_set_reset(void); | ||
| 27 | void usb_device_state_init(void); | ||
| 28 | |||
| 29 | enum usb_device_state { | ||
| 30 | USB_DEVICE_STATE_NO_INIT = 0, // We're in this state before calling usb_device_state_init() | ||
| 31 | USB_DEVICE_STATE_INIT = 1, // Can consume up to 100mA | ||
| 32 | USB_DEVICE_STATE_CONFIGURED = 2, // Can consume up to what is specified in configuration descriptor, typically 500mA | ||
| 33 | USB_DEVICE_STATE_SUSPEND = 3 // Can consume only suspend current | ||
| 34 | }; | ||
| 35 | |||
| 36 | extern enum usb_device_state usb_device_state; | ||
| 37 | |||
| 38 | void notify_usb_device_state_change_kb(enum usb_device_state usb_device_state); | ||
| 39 | void notify_usb_device_state_change_user(enum usb_device_state usb_device_state); | ||
diff --git a/quantum/visualizer/LICENSE.md b/quantum/visualizer/LICENSE.md deleted file mode 100644 index 22d4c3f08..000000000 --- a/quantum/visualizer/LICENSE.md +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | The files in this project are licensed under the MIT license | ||
| 2 | It uses the following libraries | ||
| 3 | uGFX - with it's own license, see the license.html file in the uGFX subfolder for more information | ||
| 4 | tmk_core - is indirectly used and not included in the repository. It's licensed under the GPLv2 license | ||
| 5 | Chibios - which is used by tmk_core is licensed under GPLv3. | ||
| 6 | |||
| 7 | Therefore the effective license for any project using the library is GPLv3 | ||
| 8 | |||
| 9 | The MIT License (MIT) | ||
| 10 | |||
| 11 | Copyright (c) 2016 Fred Sundvik | ||
| 12 | |||
| 13 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 14 | of this software and associated documentation files (the "Software"), to deal | ||
| 15 | in the Software without restriction, including without limitation the rights | ||
| 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 17 | copies of the Software, and to permit persons to whom the Software is | ||
| 18 | furnished to do so, subject to the following conditions: | ||
| 19 | |||
| 20 | The above copyright notice and this permission notice shall be included in all | ||
| 21 | copies or substantial portions of the Software. | ||
| 22 | |||
| 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 29 | SOFTWARE. | ||
diff --git a/quantum/visualizer/common_gfxconf.h b/quantum/visualizer/common_gfxconf.h deleted file mode 100644 index e0735b37d..000000000 --- a/quantum/visualizer/common_gfxconf.h +++ /dev/null | |||
| @@ -1,354 +0,0 @@ | |||
| 1 | /** | ||
| 2 | * This file has a different license to the rest of the uGFX system. | ||
| 3 | * You can copy, modify and distribute this file as you see fit. | ||
| 4 | * You do not need to publish your source modifications to this file. | ||
| 5 | * The only thing you are not permitted to do is to relicense it | ||
| 6 | * under a different license. | ||
| 7 | */ | ||
| 8 | |||
| 9 | /** | ||
| 10 | * Copy this file into your project directory and rename it as gfxconf.h | ||
| 11 | * Edit your copy to turn on the uGFX features you want to use. | ||
| 12 | * The values below are the defaults. | ||
| 13 | * | ||
| 14 | * Only remove the comments from lines where you want to change the | ||
| 15 | * default value. This allows definitions to be included from | ||
| 16 | * driver makefiles when required and provides the best future | ||
| 17 | * compatibility for your project. | ||
| 18 | * | ||
| 19 | * Please use spaces instead of tabs in this file. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #pragma once | ||
| 23 | |||
| 24 | /////////////////////////////////////////////////////////////////////////// | ||
| 25 | // GFX - Compatibility options // | ||
| 26 | /////////////////////////////////////////////////////////////////////////// | ||
| 27 | //#define GFX_COMPAT_V2 GFXON | ||
| 28 | //#define GFX_COMPAT_OLDCOLORS GFXON | ||
| 29 | |||
| 30 | /////////////////////////////////////////////////////////////////////////// | ||
| 31 | // GOS - One of these must be defined, preferably in your Makefile // | ||
| 32 | /////////////////////////////////////////////////////////////////////////// | ||
| 33 | //#define GFX_USE_OS_CHIBIOS GFXOFF | ||
| 34 | //#define GFX_USE_OS_FREERTOS GFXOFF | ||
| 35 | // #define GFX_FREERTOS_USE_TRACE GFXOFF | ||
| 36 | //#define GFX_USE_OS_WIN32 GFXOFF | ||
| 37 | //#define GFX_USE_OS_LINUX GFXOFF | ||
| 38 | //#define GFX_USE_OS_OSX GFXOFF | ||
| 39 | //#define GFX_USE_OS_ECOS GFXOFF | ||
| 40 | //#define GFX_USE_OS_RAWRTOS GFXOFF | ||
| 41 | //#define GFX_USE_OS_ARDUINO GFXOFF | ||
| 42 | //#define GFX_USE_OS_KEIL GFXOFF | ||
| 43 | //#define GFX_USE_OS_RTX5 GFXOFF | ||
| 44 | //#define GFX_USE_OS_CMSIS GFXOFF | ||
| 45 | //#define GFX_USE_OS_CMSIS2 GFXOFF | ||
| 46 | //#define GFX_USE_OS_RAW32 GFXOFF | ||
| 47 | //#define GFX_USE_OS_ZEPHYR GFXOFF | ||
| 48 | //#define GFX_USE_OS_NIOS GFXOFF | ||
| 49 | //#define GFX_USE_OS_QT GFXOFF | ||
| 50 | // #define INTERRUPTS_OFF() optional_code | ||
| 51 | // #define INTERRUPTS_ON() optional_code | ||
| 52 | |||
| 53 | // Options that (should where relevant) apply to all operating systems | ||
| 54 | #define GFX_NO_INLINE GFXON | ||
| 55 | // #define GFX_COMPILER GFX_COMPILER_UNKNOWN | ||
| 56 | // #define GFX_SHOW_COMPILER GFXOFF | ||
| 57 | // #define GFX_CPU GFX_CPU_UNKNOWN | ||
| 58 | // #define GFX_CPU_NO_ALIGNMENT_FAULTS GFXOFF | ||
| 59 | // #define GFX_CPU_ENDIAN GFX_CPU_ENDIAN_UNKNOWN | ||
| 60 | // #define GFX_OS_HEAP_SIZE 0 | ||
| 61 | // #define GFX_OS_NO_INIT GFXOFF | ||
| 62 | // #define GFX_OS_INIT_NO_WARNING GFXOFF | ||
| 63 | // #define GFX_OS_PRE_INIT_FUNCTION myHardwareInitRoutine | ||
| 64 | // #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine | ||
| 65 | // #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine | ||
| 66 | // #define GFX_OS_CALL_UGFXMAIN GFXOFF | ||
| 67 | // #define GFX_OS_UGFXMAIN_STACKSIZE 0 | ||
| 68 | // #define GFX_EMULATE_MALLOC GFXOFF | ||
| 69 | // #define GFX_MEM_LT64K GFXOFF | ||
| 70 | |||
| 71 | /////////////////////////////////////////////////////////////////////////// | ||
| 72 | // GDISP // | ||
| 73 | /////////////////////////////////////////////////////////////////////////// | ||
| 74 | #define GFX_USE_GDISP GFXON | ||
| 75 | |||
| 76 | //#define GDISP_NEED_AUTOFLUSH GFXOFF | ||
| 77 | //#define GDISP_NEED_TIMERFLUSH GFXOFF | ||
| 78 | //#define GDISP_NEED_VALIDATION GFXON | ||
| 79 | //#define GDISP_NEED_CLIP GFXON | ||
| 80 | #define GDISP_NEED_CIRCLE GFXON | ||
| 81 | //#define GDISP_NEED_DUALCIRCLE GFXOFF | ||
| 82 | #define GDISP_NEED_ELLIPSE GFXON | ||
| 83 | #define GDISP_NEED_ARC GFXON | ||
| 84 | #define GDISP_NEED_ARCSECTORS GFXON | ||
| 85 | #define GDISP_NEED_CONVEX_POLYGON GFXON | ||
| 86 | //#define GDISP_NEED_SCROLL GFXOFF | ||
| 87 | #define GDISP_NEED_PIXELREAD GFXON | ||
| 88 | #define GDISP_NEED_CONTROL GFXON | ||
| 89 | //#define GDISP_NEED_QUERY GFXOFF | ||
| 90 | //#define GDISP_NEED_MULTITHREAD GFXOFF | ||
| 91 | //#define GDISP_NEED_STREAMING GFXOFF | ||
| 92 | #define GDISP_NEED_TEXT GFXON | ||
| 93 | // #define GDISP_NEED_TEXT_WORDWRAP GFXOFF | ||
| 94 | // #define GDISP_NEED_TEXT_BOXPADLR 1 | ||
| 95 | // #define GDISP_NEED_TEXT_BOXPADTB 1 | ||
| 96 | // #define GDISP_NEED_ANTIALIAS GFXOFF | ||
| 97 | // #define GDISP_NEED_UTF8 GFXOFF | ||
| 98 | #define GDISP_NEED_TEXT_KERNING GFXON | ||
| 99 | // #define GDISP_INCLUDE_FONT_UI1 GFXOFF | ||
| 100 | // #define GDISP_INCLUDE_FONT_UI2 GFXOFF // The smallest preferred font. | ||
| 101 | // #define GDISP_INCLUDE_FONT_LARGENUMBERS GFXOFF | ||
| 102 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS10 GFXOFF | ||
| 103 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS12 GFXOFF | ||
| 104 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS16 GFXOFF | ||
| 105 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS20 GFXOFF | ||
| 106 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS24 GFXOFF | ||
| 107 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS32 GFXOFF | ||
| 108 | #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 GFXON | ||
| 109 | // #define GDISP_INCLUDE_FONT_FIXED_10X20 GFXOFF | ||
| 110 | // #define GDISP_INCLUDE_FONT_FIXED_7X14 GFXOFF | ||
| 111 | #define GDISP_INCLUDE_FONT_FIXED_5X8 GFXON | ||
| 112 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA GFXOFF | ||
| 113 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA GFXOFF | ||
| 114 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA GFXOFF | ||
| 115 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA GFXOFF | ||
| 116 | // #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA GFXOFF | ||
| 117 | // #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA GFXOFF | ||
| 118 | // #define GDISP_INCLUDE_USER_FONTS GFXOFF | ||
| 119 | |||
| 120 | //#define GDISP_NEED_IMAGE GFXOFF | ||
| 121 | // #define GDISP_NEED_IMAGE_NATIVE GFXOFF | ||
| 122 | // #define GDISP_NEED_IMAGE_GIF GFXOFF | ||
| 123 | // #define GDISP_IMAGE_GIF_BLIT_BUFFER_SIZE 32 | ||
| 124 | // #define GDISP_NEED_IMAGE_BMP GFXOFF | ||
| 125 | // #define GDISP_NEED_IMAGE_BMP_1 GFXON | ||
| 126 | // #define GDISP_NEED_IMAGE_BMP_4 GFXON | ||
| 127 | // #define GDISP_NEED_IMAGE_BMP_4_RLE GFXON | ||
| 128 | // #define GDISP_NEED_IMAGE_BMP_8 GFXON | ||
| 129 | // #define GDISP_NEED_IMAGE_BMP_8_RLE GFXON | ||
| 130 | // #define GDISP_NEED_IMAGE_BMP_16 GFXON | ||
| 131 | // #define GDISP_NEED_IMAGE_BMP_24 GFXON | ||
| 132 | // #define GDISP_NEED_IMAGE_BMP_32 GFXON | ||
| 133 | // #define GDISP_IMAGE_BMP_BLIT_BUFFER_SIZE 32 | ||
| 134 | // #define GDISP_NEED_IMAGE_JPG GFXOFF | ||
| 135 | // #define GDISP_NEED_IMAGE_PNG GFXOFF | ||
| 136 | // #define GDISP_NEED_IMAGE_PNG_INTERLACED GFXOFF | ||
| 137 | // #define GDISP_NEED_IMAGE_PNG_TRANSPARENCY GFXON | ||
| 138 | // #define GDISP_NEED_IMAGE_PNG_BACKGROUND GFXON | ||
| 139 | // #define GDISP_NEED_IMAGE_PNG_ALPHACLIFF 32 | ||
| 140 | // #define GDISP_NEED_IMAGE_PNG_PALETTE_124 GFXON | ||
| 141 | // #define GDISP_NEED_IMAGE_PNG_PALETTE_8 GFXON | ||
| 142 | // #define GDISP_NEED_IMAGE_PNG_GRAYSCALE_124 GFXON | ||
| 143 | // #define GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 GFXON | ||
| 144 | // #define GDISP_NEED_IMAGE_PNG_GRAYSCALE_16 GFXON | ||
| 145 | // #define GDISP_NEED_IMAGE_PNG_GRAYALPHA_8 GFXON | ||
| 146 | // #define GDISP_NEED_IMAGE_PNG_GRAYALPHA_16 GFXON | ||
| 147 | // #define GDISP_NEED_IMAGE_PNG_RGB_8 GFXON | ||
| 148 | // #define GDISP_NEED_IMAGE_PNG_RGB_16 GFXON | ||
| 149 | // #define GDISP_NEED_IMAGE_PNG_RGBALPHA_8 GFXON | ||
| 150 | // #define GDISP_NEED_IMAGE_PNG_RGBALPHA_16 GFXON | ||
| 151 | // #define GDISP_IMAGE_PNG_BLIT_BUFFER_SIZE 32 | ||
| 152 | // #define GDISP_IMAGE_PNG_FILE_BUFFER_SIZE 8 | ||
| 153 | // #define GDISP_IMAGE_PNG_Z_BUFFER_SIZE 32768 | ||
| 154 | // #define GDISP_NEED_IMAGE_ACCOUNTING GFXOFF | ||
| 155 | |||
| 156 | //#define GDISP_NEED_PIXMAP GFXOFF | ||
| 157 | // #define GDISP_NEED_PIXMAP_IMAGE GFXOFF | ||
| 158 | |||
| 159 | //#define GDISP_DEFAULT_ORIENTATION gOrientationLandscape // If not defined the native hardware orientation is used. | ||
| 160 | //#define GDISP_LINEBUF_SIZE 128 | ||
| 161 | //#define GDISP_STARTUP_COLOR GFX_BLACK | ||
| 162 | #define GDISP_NEED_STARTUP_LOGO GFXOFF | ||
| 163 | |||
| 164 | //#define GDISP_TOTAL_DISPLAYS 1 | ||
| 165 | |||
| 166 | //#define GDISP_DRIVER_LIST GDISPVMT_Win32, GDISPVMT_Win32 | ||
| 167 | #ifdef GDISP_DRIVER_LIST | ||
| 168 | // // For code and speed optimization define as GFXON or GFXOFF if all controllers have the same capability | ||
| 169 | # define GDISP_HARDWARE_STREAM_WRITE GFXOFF | ||
| 170 | # define GDISP_HARDWARE_STREAM_READ GFXOFF | ||
| 171 | # define GDISP_HARDWARE_STREAM_POS GFXOFF | ||
| 172 | # define GDISP_HARDWARE_DRAWPIXEL GFXON | ||
| 173 | # define GDISP_HARDWARE_CLEARS GFXOFF | ||
| 174 | # define GDISP_HARDWARE_FILLS GFXOFF | ||
| 175 | //#define GDISP_HARDWARE_BITFILLS GFXOFF | ||
| 176 | # define GDISP_HARDWARE_SCROLL GFXOFF | ||
| 177 | # define GDISP_HARDWARE_PIXELREAD GFXON | ||
| 178 | # define GDISP_HARDWARE_CONTROL GFXON | ||
| 179 | # define GDISP_HARDWARE_QUERY GFXOFF | ||
| 180 | # define GDISP_HARDWARE_CLIP GFXOFF | ||
| 181 | |||
| 182 | # define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 | ||
| 183 | #endif | ||
| 184 | |||
| 185 | #define GDISP_USE_GFXNET GFXOFF | ||
| 186 | // #define GDISP_GFXNET_PORT 13001 | ||
| 187 | // #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP GFXOFF | ||
| 188 | // #define GDISP_DONT_WAIT_FOR_NET_DISPLAY GFXOFF | ||
| 189 | // #define GDISP_GFXNET_UNSAFE_SOCKETS GFXOFF | ||
| 190 | |||
| 191 | /////////////////////////////////////////////////////////////////////////// | ||
| 192 | // GWIN // | ||
| 193 | /////////////////////////////////////////////////////////////////////////// | ||
| 194 | #define GFX_USE_GWIN GFXOFF | ||
| 195 | |||
| 196 | //#define GWIN_NEED_WINDOWMANAGER GFXOFF | ||
| 197 | // #define GWIN_REDRAW_IMMEDIATE GFXOFF | ||
| 198 | // #define GWIN_REDRAW_SINGLEOP GFXOFF | ||
| 199 | // #define GWIN_NEED_FLASHING GFXOFF | ||
| 200 | // #define GWIN_FLASHING_PERIOD 250 | ||
| 201 | |||
| 202 | //#define GWIN_NEED_CONSOLE GFXOFF | ||
| 203 | // #define GWIN_CONSOLE_USE_HISTORY GFXOFF | ||
| 204 | // #define GWIN_CONSOLE_HISTORY_AVERAGING GFXOFF | ||
| 205 | // #define GWIN_CONSOLE_HISTORY_ATCREATE GFXOFF | ||
| 206 | // #define GWIN_CONSOLE_ESCSEQ GFXOFF | ||
| 207 | // #define GWIN_CONSOLE_USE_BASESTREAM GFXOFF | ||
| 208 | // #define GWIN_CONSOLE_USE_FLOAT GFXOFF | ||
| 209 | //#define GWIN_NEED_GRAPH GFXOFF | ||
| 210 | //#define GWIN_NEED_GL3D GFXOFF | ||
| 211 | |||
| 212 | //#define GWIN_NEED_WIDGET GFXOFF | ||
| 213 | //#define GWIN_FOCUS_HIGHLIGHT_WIDTH 1 | ||
| 214 | // #define GWIN_NEED_LABEL GFXOFF | ||
| 215 | // #define GWIN_LABEL_ATTRIBUTE GFXOFF | ||
| 216 | // #define GWIN_NEED_BUTTON GFXOFF | ||
| 217 | // #define GWIN_BUTTON_LAZY_RELEASE GFXOFF | ||
| 218 | // #define GWIN_NEED_SLIDER GFXOFF | ||
| 219 | // #define GWIN_SLIDER_NOSNAP GFXOFF | ||
| 220 | // #define GWIN_SLIDER_DEAD_BAND 5 | ||
| 221 | // #define GWIN_SLIDER_TOGGLE_INC 20 | ||
| 222 | // #define GWIN_NEED_CHECKBOX GFXOFF | ||
| 223 | // #define GWIN_NEED_IMAGE GFXOFF | ||
| 224 | // #define GWIN_NEED_IMAGE_ANIMATION GFXOFF | ||
| 225 | // #define GWIN_NEED_RADIO GFXOFF | ||
| 226 | // #define GWIN_NEED_LIST GFXOFF | ||
| 227 | // #define GWIN_NEED_LIST_IMAGES GFXOFF | ||
| 228 | // #define GWIN_NEED_PROGRESSBAR GFXOFF | ||
| 229 | // #define GWIN_PROGRESSBAR_AUTO GFXOFF | ||
| 230 | // #define GWIN_NEED_KEYBOARD GFXOFF | ||
| 231 | // #define GWIN_KEYBOARD_DEFAULT_LAYOUT VirtualKeyboard_English1 | ||
| 232 | // #define GWIN_NEED_KEYBOARD_ENGLISH1 GFXON | ||
| 233 | // #define GWIN_NEED_TEXTEDIT GFXOFF | ||
| 234 | // #define GWIN_FLAT_STYLING GFXOFF | ||
| 235 | // #define GWIN_WIDGET_TAGS GFXOFF | ||
| 236 | |||
| 237 | //#define GWIN_NEED_CONTAINERS GFXOFF | ||
| 238 | // #define GWIN_NEED_CONTAINER GFXOFF | ||
| 239 | // #define GWIN_NEED_FRAME GFXOFF | ||
| 240 | // #define GWIN_NEED_TABSET GFXOFF | ||
| 241 | // #define GWIN_TABSET_TABHEIGHT 18 | ||
| 242 | |||
| 243 | /////////////////////////////////////////////////////////////////////////// | ||
| 244 | // GTRANS // | ||
| 245 | /////////////////////////////////////////////////////////////////////////// | ||
| 246 | //#define GFX_USE_GTRANS GFXOFF | ||
| 247 | |||
| 248 | /////////////////////////////////////////////////////////////////////////// | ||
| 249 | // GEVENT // | ||
| 250 | /////////////////////////////////////////////////////////////////////////// | ||
| 251 | #define GFX_USE_GEVENT GFXON | ||
| 252 | |||
| 253 | //#define GEVENT_ASSERT_NO_RESOURCE GFXOFF | ||
| 254 | //#define GEVENT_MAXIMUM_SIZE 32 | ||
| 255 | //#define GEVENT_MAX_SOURCE_LISTENERS 32 | ||
| 256 | |||
| 257 | /////////////////////////////////////////////////////////////////////////// | ||
| 258 | // GTIMER // | ||
| 259 | /////////////////////////////////////////////////////////////////////////// | ||
| 260 | #define GFX_USE_GTIMER GFXOFF | ||
| 261 | |||
| 262 | //#define GTIMER_THREAD_PRIORITY gThreadpriorityHigh | ||
| 263 | //#define GTIMER_THREAD_WORKAREA_SIZE 2048 | ||
| 264 | |||
| 265 | /////////////////////////////////////////////////////////////////////////// | ||
| 266 | // GQUEUE // | ||
| 267 | /////////////////////////////////////////////////////////////////////////// | ||
| 268 | #define GFX_USE_GQUEUE GFXOFF | ||
| 269 | |||
| 270 | //#define GQUEUE_NEED_ASYNC GFXOFF | ||
| 271 | //#define GQUEUE_NEED_GSYNC GFXOFF | ||
| 272 | //#define GQUEUE_NEED_FSYNC GFXOFF | ||
| 273 | //#define GQUEUE_NEED_BUFFERS GFXOFF | ||
| 274 | |||
| 275 | /////////////////////////////////////////////////////////////////////////// | ||
| 276 | // GINPUT // | ||
| 277 | /////////////////////////////////////////////////////////////////////////// | ||
| 278 | #define GFX_USE_GINPUT GFXOFF | ||
| 279 | |||
| 280 | //#define GINPUT_NEED_MOUSE GFXOFF | ||
| 281 | // #define GINPUT_TOUCH_STARTRAW GFXOFF | ||
| 282 | // #define GINPUT_TOUCH_NOTOUCH GFXOFF | ||
| 283 | // #define GINPUT_TOUCH_NOCALIBRATE GFXOFF | ||
| 284 | // #define GINPUT_TOUCH_NOCALIBRATE_GUI GFXOFF | ||
| 285 | // #define GINPUT_MOUSE_POLL_PERIOD 25 | ||
| 286 | // #define GINPUT_MOUSE_CLICK_TIME 300 | ||
| 287 | // #define GINPUT_TOUCH_CXTCLICK_TIME 700 | ||
| 288 | // #define GINPUT_TOUCH_USER_CALIBRATION_LOAD GFXOFF | ||
| 289 | // #define GINPUT_TOUCH_USER_CALIBRATION_SAVE GFXOFF | ||
| 290 | // #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32 | ||
| 291 | // #define GINPUT_TOUCH_CALIBRATION_FONT1 "* Double" | ||
| 292 | // #define GINPUT_TOUCH_CALIBRATION_FONT2 "* Narrow" | ||
| 293 | // #define GINPUT_TOUCH_CALIBRATION_TITLE "Calibration" | ||
| 294 | // #define GINPUT_TOUCH_CALIBRATION_ERROR "Calibration Failed!" | ||
| 295 | //#define GINPUT_NEED_KEYBOARD GFXOFF | ||
| 296 | // #define GINPUT_KEYBOARD_POLL_PERIOD 200 | ||
| 297 | // #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32 | ||
| 298 | // #define GKEYBOARD_LAYOUT_OFF GFXOFF | ||
| 299 | // #define GKEYBOARD_LAYOUT_SCANCODE2_US GFXOFF | ||
| 300 | //#define GINPUT_NEED_TOGGLE GFXOFF | ||
| 301 | //#define GINPUT_NEED_DIAL GFXOFF | ||
| 302 | |||
| 303 | /////////////////////////////////////////////////////////////////////////// | ||
| 304 | // GFILE // | ||
| 305 | /////////////////////////////////////////////////////////////////////////// | ||
| 306 | #define GFX_USE_GFILE GFXOFF | ||
| 307 | |||
| 308 | //#define GFILE_NEED_PRINTG GFXOFF | ||
| 309 | //#define GFILE_NEED_SCANG GFXOFF | ||
| 310 | //#define GFILE_NEED_STRINGS GFXOFF | ||
| 311 | //#define GFILE_NEED_FILELISTS GFXOFF | ||
| 312 | //#define GFILE_NEED_STDIO GFXOFF | ||
| 313 | //#define GFILE_NEED_NOAUTOMOUNT GFXOFF | ||
| 314 | //#define GFILE_NEED_NOAUTOSYNC GFXOFF | ||
| 315 | |||
| 316 | //#define GFILE_NEED_MEMFS GFXOFF | ||
| 317 | //#define GFILE_NEED_ROMFS GFXOFF | ||
| 318 | //#define GFILE_NEED_RAMFS GFXOFF | ||
| 319 | //#define GFILE_NEED_FATFS GFXOFF | ||
| 320 | //#define GFILE_NEED_NATIVEFS GFXOFF | ||
| 321 | //#define GFILE_NEED_CHBIOSFS GFXOFF | ||
| 322 | //#define GFILE_NEED_USERFS GFXOFF | ||
| 323 | |||
| 324 | //#define GFILE_ALLOW_FLOATS GFXOFF | ||
| 325 | //#define GFILE_ALLOW_DEVICESPECIFIC GFXOFF | ||
| 326 | //#define GFILE_MAX_GFILES 3 | ||
| 327 | |||
| 328 | /////////////////////////////////////////////////////////////////////////// | ||
| 329 | // GADC // | ||
| 330 | /////////////////////////////////////////////////////////////////////////// | ||
| 331 | #define GFX_USE_GADC GFXOFF | ||
| 332 | // #define GADC_MAX_LOWSPEED_DEVICES 4 | ||
| 333 | |||
| 334 | /////////////////////////////////////////////////////////////////////////// | ||
| 335 | // GAUDIO // | ||
| 336 | /////////////////////////////////////////////////////////////////////////// | ||
| 337 | #define GFX_USE_GAUDIO GFXOFF | ||
| 338 | // #define GAUDIO_NEED_PLAY GFXOFF | ||
| 339 | // #define GAUDIO_NEED_RECORD GFXOFF | ||
| 340 | |||
| 341 | /////////////////////////////////////////////////////////////////////////// | ||
| 342 | // GMISC // | ||
| 343 | /////////////////////////////////////////////////////////////////////////// | ||
| 344 | #define GFX_USE_GMISC GFXON | ||
| 345 | |||
| 346 | //#define GMISC_NEED_ARRAYOPS GFXOFF | ||
| 347 | //#define GMISC_NEED_FASTTRIG GFXOFF | ||
| 348 | //#define GMISC_NEED_FIXEDTRIG GFXOFF | ||
| 349 | //#define GMISC_NEED_INVSQRT GFXOFF | ||
| 350 | // #define GMISC_INVSQRT_MIXED_ENDIAN GFXOFF | ||
| 351 | // #define GMISC_INVSQRT_REAL_SLOW GFXOFF | ||
| 352 | #define GMISC_NEED_MATRIXFLOAT2D GFXON | ||
| 353 | #define GMISC_NEED_MATRIXFIXED2D GFXOFF | ||
| 354 | //#define GMISC_NEED_HITTEST_POLY GFXOFF | ||
diff --git a/quantum/visualizer/default_animations.c b/quantum/visualizer/default_animations.c deleted file mode 100644 index 2f43c67cc..000000000 --- a/quantum/visualizer/default_animations.c +++ /dev/null | |||
| @@ -1,177 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #if defined(VISUALIZER_ENABLE) | ||
| 18 | |||
| 19 | # include "default_animations.h" | ||
| 20 | # include "visualizer.h" | ||
| 21 | # ifdef LCD_ENABLE | ||
| 22 | # include "lcd_keyframes.h" | ||
| 23 | # endif | ||
| 24 | # ifdef LCD_BACKLIGHT_ENABLE | ||
| 25 | # include "lcd_backlight_keyframes.h" | ||
| 26 | # endif | ||
| 27 | |||
| 28 | # ifdef BACKLIGHT_ENABLE | ||
| 29 | # include "led_backlight_keyframes.h" | ||
| 30 | # endif | ||
| 31 | |||
| 32 | # include "visualizer_keyframes.h" | ||
| 33 | |||
| 34 | # if defined(LCD_ENABLE) || defined(LCD_BACKLIGHT_ENABLE) || defined(BACKLIGHT_ENABLE) | ||
| 35 | |||
| 36 | static bool keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 37 | # ifdef LCD_ENABLE | ||
| 38 | lcd_keyframe_enable(animation, state); | ||
| 39 | # endif | ||
| 40 | # ifdef LCD_BACKLIGHT_ENABLE | ||
| 41 | lcd_backlight_keyframe_enable(animation, state); | ||
| 42 | # endif | ||
| 43 | # ifdef BACKLIGHT_ENABLE | ||
| 44 | led_backlight_keyframe_enable(animation, state); | ||
| 45 | # endif | ||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | static bool keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 50 | # ifdef LCD_ENABLE | ||
| 51 | lcd_keyframe_disable(animation, state); | ||
| 52 | # endif | ||
| 53 | # ifdef LCD_BACKLIGHT_ENABLE | ||
| 54 | lcd_backlight_keyframe_disable(animation, state); | ||
| 55 | # endif | ||
| 56 | # ifdef BACKLIGHT_ENABLE | ||
| 57 | led_backlight_keyframe_disable(animation, state); | ||
| 58 | # endif | ||
| 59 | return false; | ||
| 60 | } | ||
| 61 | |||
| 62 | static bool keyframe_fade_in(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 63 | bool ret = false; | ||
| 64 | # ifdef LCD_BACKLIGHT_ENABLE | ||
| 65 | ret |= lcd_backlight_keyframe_animate_color(animation, state); | ||
| 66 | # endif | ||
| 67 | # ifdef BACKLIGHT_ENABLE | ||
| 68 | ret |= led_backlight_keyframe_fade_in_all(animation, state); | ||
| 69 | # endif | ||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | static bool keyframe_fade_out(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 74 | bool ret = false; | ||
| 75 | # ifdef LCD_BACKLIGHT_ENABLE | ||
| 76 | ret |= lcd_backlight_keyframe_animate_color(animation, state); | ||
| 77 | # endif | ||
| 78 | # ifdef BACKLIGHT_ENABLE | ||
| 79 | ret |= led_backlight_keyframe_fade_out_all(animation, state); | ||
| 80 | # endif | ||
| 81 | return ret; | ||
| 82 | } | ||
| 83 | |||
| 84 | // Don't worry, if the startup animation is long, you can use the keyboard like normal | ||
| 85 | // during that time | ||
| 86 | keyframe_animation_t default_startup_animation = { | ||
| 87 | # if LCD_ENABLE | ||
| 88 | .num_frames = 3, | ||
| 89 | # else | ||
| 90 | .num_frames = 2, | ||
| 91 | # endif | ||
| 92 | .loop = false, | ||
| 93 | .frame_lengths = {0, | ||
| 94 | # if LCD_ENABLE | ||
| 95 | 0, | ||
| 96 | # endif | ||
| 97 | gfxMillisecondsToTicks(5000)}, | ||
| 98 | .frame_functions = | ||
| 99 | { | ||
| 100 | keyframe_enable, | ||
| 101 | # if LCD_ENABLE | ||
| 102 | lcd_keyframe_draw_logo, | ||
| 103 | # endif | ||
| 104 | keyframe_fade_in, | ||
| 105 | }, | ||
| 106 | }; | ||
| 107 | |||
| 108 | keyframe_animation_t default_suspend_animation = { | ||
| 109 | # if LCD_ENABLE | ||
| 110 | .num_frames = 3, | ||
| 111 | # else | ||
| 112 | .num_frames = 2, | ||
| 113 | # endif | ||
| 114 | .loop = false, | ||
| 115 | .frame_lengths = | ||
| 116 | { | ||
| 117 | # if LCD_ENABLE | ||
| 118 | 0, | ||
| 119 | # endif | ||
| 120 | gfxMillisecondsToTicks(1000), 0}, | ||
| 121 | .frame_functions = | ||
| 122 | { | ||
| 123 | # if LCD_ENABLE | ||
| 124 | lcd_keyframe_display_layer_text, | ||
| 125 | # endif | ||
| 126 | keyframe_fade_out, | ||
| 127 | keyframe_disable, | ||
| 128 | }, | ||
| 129 | }; | ||
| 130 | # endif | ||
| 131 | |||
| 132 | # if defined(BACKLIGHT_ENABLE) | ||
| 133 | # define CROSSFADE_TIME 1000 | ||
| 134 | # define GRADIENT_TIME 3000 | ||
| 135 | |||
| 136 | keyframe_animation_t led_test_animation = { | ||
| 137 | .num_frames = 14, | ||
| 138 | .loop = true, | ||
| 139 | .frame_lengths = | ||
| 140 | { | ||
| 141 | gfxMillisecondsToTicks(1000), // fade in | ||
| 142 | gfxMillisecondsToTicks(1000), // no op (leds on) | ||
| 143 | gfxMillisecondsToTicks(1000), // fade out | ||
| 144 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 145 | gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in) | ||
| 146 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 147 | gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom | ||
| 148 | 0, // mirror leds | ||
| 149 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 150 | gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out) | ||
| 151 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 152 | gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom | ||
| 153 | 0, // normal leds | ||
| 154 | gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade | ||
| 155 | |||
| 156 | }, | ||
| 157 | .frame_functions = | ||
| 158 | { | ||
| 159 | led_backlight_keyframe_fade_in_all, | ||
| 160 | keyframe_no_operation, | ||
| 161 | led_backlight_keyframe_fade_out_all, | ||
| 162 | led_backlight_keyframe_crossfade, | ||
| 163 | led_backlight_keyframe_left_to_right_gradient, | ||
| 164 | led_backlight_keyframe_crossfade, | ||
| 165 | led_backlight_keyframe_top_to_bottom_gradient, | ||
| 166 | led_backlight_keyframe_mirror_orientation, | ||
| 167 | led_backlight_keyframe_crossfade, | ||
| 168 | led_backlight_keyframe_left_to_right_gradient, | ||
| 169 | led_backlight_keyframe_crossfade, | ||
| 170 | led_backlight_keyframe_top_to_bottom_gradient, | ||
| 171 | led_backlight_keyframe_normal_orientation, | ||
| 172 | led_backlight_keyframe_crossfade, | ||
| 173 | }, | ||
| 174 | }; | ||
| 175 | # endif | ||
| 176 | |||
| 177 | #endif | ||
diff --git a/quantum/visualizer/default_animations.h b/quantum/visualizer/default_animations.h deleted file mode 100644 index 9accd8977..000000000 --- a/quantum/visualizer/default_animations.h +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "visualizer.h" | ||
| 20 | |||
| 21 | // You can use these default animations, but of course you can also write your own custom ones instead | ||
| 22 | extern keyframe_animation_t default_startup_animation; | ||
| 23 | extern keyframe_animation_t default_suspend_animation; | ||
| 24 | |||
| 25 | // An animation for testing and demonstrating the led support, should probably not be used for real world | ||
| 26 | // cases | ||
| 27 | extern keyframe_animation_t led_test_animation; | ||
diff --git a/quantum/visualizer/lcd_backlight.c b/quantum/visualizer/lcd_backlight.c deleted file mode 100644 index 23978974e..000000000 --- a/quantum/visualizer/lcd_backlight.c +++ /dev/null | |||
| @@ -1,87 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "lcd_backlight.h" | ||
| 26 | #include <math.h> | ||
| 27 | |||
| 28 | static uint8_t current_hue = 0; | ||
| 29 | static uint8_t current_saturation = 0; | ||
| 30 | static uint8_t current_intensity = 0; | ||
| 31 | static uint8_t current_brightness = 0; | ||
| 32 | |||
| 33 | void lcd_backlight_init(void) { | ||
| 34 | lcd_backlight_hal_init(); | ||
| 35 | lcd_backlight_color(current_hue, current_saturation, current_intensity); | ||
| 36 | } | ||
| 37 | |||
| 38 | // This code is based on Brian Neltner's blogpost and example code | ||
| 39 | // "Why every LED light should be using HSI colorspace". | ||
| 40 | // http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi | ||
| 41 | static void hsi_to_rgb(float h, float s, float i, uint16_t* r_out, uint16_t* g_out, uint16_t* b_out) { | ||
| 42 | unsigned int r, g, b; | ||
| 43 | h = fmodf(h, 360.0f); // cycle h around to 0-360 degrees | ||
| 44 | h = 3.14159f * h / 180.0f; // Convert to radians. | ||
| 45 | s = s > 0.0f ? (s < 1.0f ? s : 1.0f) : 0.0f; // clamp s and i to interval [0,1] | ||
| 46 | i = i > 0.0f ? (i < 1.0f ? i : 1.0f) : 0.0f; | ||
| 47 | |||
| 48 | // Math! Thanks in part to Kyle Miller. | ||
| 49 | if (h < 2.09439f) { | ||
| 50 | r = 65535.0f * i / 3.0f * (1.0f + s * cos(h) / cosf(1.047196667f - h)); | ||
| 51 | g = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cos(1.047196667f - h))); | ||
| 52 | b = 65535.0f * i / 3.0f * (1.0f - s); | ||
| 53 | } else if (h < 4.188787) { | ||
| 54 | h = h - 2.09439; | ||
| 55 | g = 65535.0f * i / 3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h)); | ||
| 56 | b = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h))); | ||
| 57 | r = 65535.0f * i / 3.0f * (1.0f - s); | ||
| 58 | } else { | ||
| 59 | h = h - 4.188787; | ||
| 60 | b = 65535.0f * i / 3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h)); | ||
| 61 | r = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h))); | ||
| 62 | g = 65535.0f * i / 3.0f * (1.0f - s); | ||
| 63 | } | ||
| 64 | *r_out = r > 65535 ? 65535 : r; | ||
| 65 | *g_out = g > 65535 ? 65535 : g; | ||
| 66 | *b_out = b > 65535 ? 65535 : b; | ||
| 67 | } | ||
| 68 | |||
| 69 | void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity) { | ||
| 70 | uint16_t r, g, b; | ||
| 71 | float hue_f = 360.0f * (float)hue / 255.0f; | ||
| 72 | float saturation_f = (float)saturation / 255.0f; | ||
| 73 | float intensity_f = (float)intensity / 255.0f; | ||
| 74 | intensity_f *= (float)current_brightness / 255.0f; | ||
| 75 | hsi_to_rgb(hue_f, saturation_f, intensity_f, &r, &g, &b); | ||
| 76 | current_hue = hue; | ||
| 77 | current_saturation = saturation; | ||
| 78 | current_intensity = intensity; | ||
| 79 | lcd_backlight_hal_color(r, g, b); | ||
| 80 | } | ||
| 81 | |||
| 82 | void lcd_backlight_brightness(uint8_t b) { | ||
| 83 | current_brightness = b; | ||
| 84 | lcd_backlight_color(current_hue, current_saturation, current_intensity); | ||
| 85 | } | ||
| 86 | |||
| 87 | uint8_t lcd_get_backlight_brightness(void) { return current_brightness; } | ||
diff --git a/quantum/visualizer/lcd_backlight.h b/quantum/visualizer/lcd_backlight.h deleted file mode 100644 index 4ea5b1463..000000000 --- a/quantum/visualizer/lcd_backlight.h +++ /dev/null | |||
| @@ -1,43 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <stdint.h> | ||
| 28 | |||
| 29 | // Helper macros for storing hue, staturation and intensity as unsigned integers | ||
| 30 | #define LCD_COLOR(hue, saturation, intensity) (hue << 16 | saturation << 8 | intensity) | ||
| 31 | #define LCD_HUE(color) ((color >> 16) & 0xFF) | ||
| 32 | #define LCD_SAT(color) ((color >> 8) & 0xFF) | ||
| 33 | #define LCD_INT(color) (color & 0xFF) | ||
| 34 | |||
| 35 | static inline uint32_t change_lcd_color_intensity(uint32_t color, uint8_t new_intensity) { return (color & 0xFFFFFF00) | new_intensity; } | ||
| 36 | |||
| 37 | void lcd_backlight_init(void); | ||
| 38 | void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity); | ||
| 39 | void lcd_backlight_brightness(uint8_t b); | ||
| 40 | uint8_t lcd_get_backlight_brightness(void); | ||
| 41 | |||
| 42 | void lcd_backlight_hal_init(void); | ||
| 43 | void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b); | ||
diff --git a/quantum/visualizer/lcd_backlight_keyframes.c b/quantum/visualizer/lcd_backlight_keyframes.c deleted file mode 100644 index c13cce311..000000000 --- a/quantum/visualizer/lcd_backlight_keyframes.c +++ /dev/null | |||
| @@ -1,69 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "lcd_backlight_keyframes.h" | ||
| 18 | |||
| 19 | bool lcd_backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 20 | int frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 21 | int current_pos = frame_length - animation->time_left_in_frame; | ||
| 22 | uint8_t t_h = LCD_HUE(state->target_lcd_color); | ||
| 23 | uint8_t t_s = LCD_SAT(state->target_lcd_color); | ||
| 24 | uint8_t t_i = LCD_INT(state->target_lcd_color); | ||
| 25 | uint8_t p_h = LCD_HUE(state->prev_lcd_color); | ||
| 26 | uint8_t p_s = LCD_SAT(state->prev_lcd_color); | ||
| 27 | uint8_t p_i = LCD_INT(state->prev_lcd_color); | ||
| 28 | |||
| 29 | uint8_t d_h1 = t_h - p_h; // Modulo arithmetic since we want to wrap around | ||
| 30 | int d_h2 = t_h - p_h; | ||
| 31 | // Chose the shortest way around | ||
| 32 | int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1; | ||
| 33 | int d_s = t_s - p_s; | ||
| 34 | int d_i = t_i - p_i; | ||
| 35 | |||
| 36 | int hue = (d_h * current_pos) / frame_length; | ||
| 37 | int sat = (d_s * current_pos) / frame_length; | ||
| 38 | int intensity = (d_i * current_pos) / frame_length; | ||
| 39 | // dprintf("%X -> %X = %X\n", p_h, t_h, hue); | ||
| 40 | hue += p_h; | ||
| 41 | sat += p_s; | ||
| 42 | intensity += p_i; | ||
| 43 | state->current_lcd_color = LCD_COLOR(hue, sat, intensity); | ||
| 44 | lcd_backlight_color(LCD_HUE(state->current_lcd_color), LCD_SAT(state->current_lcd_color), LCD_INT(state->current_lcd_color)); | ||
| 45 | |||
| 46 | return true; | ||
| 47 | } | ||
| 48 | |||
| 49 | bool lcd_backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 50 | (void)animation; | ||
| 51 | state->prev_lcd_color = state->target_lcd_color; | ||
| 52 | state->current_lcd_color = state->target_lcd_color; | ||
| 53 | lcd_backlight_color(LCD_HUE(state->current_lcd_color), LCD_SAT(state->current_lcd_color), LCD_INT(state->current_lcd_color)); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | bool lcd_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 58 | (void)animation; | ||
| 59 | (void)state; | ||
| 60 | lcd_backlight_hal_color(0, 0, 0); | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | |||
| 64 | bool lcd_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 65 | (void)animation; | ||
| 66 | (void)state; | ||
| 67 | lcd_backlight_color(LCD_HUE(state->current_lcd_color), LCD_SAT(state->current_lcd_color), LCD_INT(state->current_lcd_color)); | ||
| 68 | return false; | ||
| 69 | } | ||
diff --git a/quantum/visualizer/lcd_backlight_keyframes.h b/quantum/visualizer/lcd_backlight_keyframes.h deleted file mode 100644 index 88768dd4a..000000000 --- a/quantum/visualizer/lcd_backlight_keyframes.h +++ /dev/null | |||
| @@ -1,27 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "visualizer.h" | ||
| 20 | |||
| 21 | // Animates the LCD backlight color between the current color and the target color (of the state) | ||
| 22 | bool lcd_backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 23 | // Sets the backlight color to the target color | ||
| 24 | bool lcd_backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 25 | |||
| 26 | bool lcd_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 27 | bool lcd_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state); | ||
diff --git a/quantum/visualizer/lcd_keyframes.c b/quantum/visualizer/lcd_keyframes.c deleted file mode 100644 index 1d6f3dca1..000000000 --- a/quantum/visualizer/lcd_keyframes.c +++ /dev/null | |||
| @@ -1,184 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "lcd_keyframes.h" | ||
| 18 | #include <string.h> | ||
| 19 | #include "action_util.h" | ||
| 20 | #include "led.h" | ||
| 21 | #include "resources/resources.h" | ||
| 22 | |||
| 23 | bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 24 | (void)animation; | ||
| 25 | gdispClear(White); | ||
| 26 | gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black); | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | |||
| 30 | static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) { | ||
| 31 | for (int i = 0; i < 16; i++) { | ||
| 32 | uint32_t mask = (1u << i); | ||
| 33 | if (default_layer & mask) { | ||
| 34 | if (layer & mask) { | ||
| 35 | *buffer = 'B'; | ||
| 36 | } else { | ||
| 37 | *buffer = 'D'; | ||
| 38 | } | ||
| 39 | } else if (layer & mask) { | ||
| 40 | *buffer = '1'; | ||
| 41 | } else { | ||
| 42 | *buffer = '0'; | ||
| 43 | } | ||
| 44 | ++buffer; | ||
| 45 | |||
| 46 | if (i == 3 || i == 7 || i == 11) { | ||
| 47 | *buffer = ' '; | ||
| 48 | ++buffer; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | *buffer = 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 55 | (void)animation; | ||
| 56 | const char* layer_help = "1=On D=Default B=Both"; | ||
| 57 | char layer_buffer[16 + 4]; // 3 spaces and one null terminator | ||
| 58 | gdispClear(White); | ||
| 59 | gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black); | ||
| 60 | format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer); | ||
| 61 | gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black); | ||
| 62 | format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer); | ||
| 63 | gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black); | ||
| 64 | return false; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void format_mods_bitmap_string(uint8_t mods, char* buffer) { | ||
| 68 | *buffer = ' '; | ||
| 69 | ++buffer; | ||
| 70 | |||
| 71 | for (int i = 0; i < 8; i++) { | ||
| 72 | uint32_t mask = (1u << i); | ||
| 73 | if (mods & mask) { | ||
| 74 | *buffer = '1'; | ||
| 75 | } else { | ||
| 76 | *buffer = '0'; | ||
| 77 | } | ||
| 78 | ++buffer; | ||
| 79 | |||
| 80 | if (i == 3) { | ||
| 81 | *buffer = ' '; | ||
| 82 | ++buffer; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | *buffer = 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 89 | (void)animation; | ||
| 90 | |||
| 91 | const char* title = "Modifier states"; | ||
| 92 | const char* mods_header = " CSAG CSAG "; | ||
| 93 | char status_buffer[12]; | ||
| 94 | |||
| 95 | gdispClear(White); | ||
| 96 | gdispDrawString(0, 0, title, state->font_fixed5x8, Black); | ||
| 97 | gdispDrawString(0, 10, mods_header, state->font_fixed5x8, Black); | ||
| 98 | format_mods_bitmap_string(state->status.mods, status_buffer); | ||
| 99 | gdispDrawString(0, 20, status_buffer, state->font_fixed5x8, Black); | ||
| 100 | |||
| 101 | return false; | ||
| 102 | } | ||
| 103 | |||
| 104 | #define LED_STATE_STRING_SIZE sizeof("NUM CAPS SCRL COMP KANA") | ||
| 105 | |||
| 106 | static void get_led_state_string(char* output, visualizer_state_t* state) { | ||
| 107 | uint8_t pos = 0; | ||
| 108 | |||
| 109 | if (state->status.leds & (1u << USB_LED_NUM_LOCK)) { | ||
| 110 | memcpy(output + pos, "NUM ", 4); | ||
| 111 | pos += 4; | ||
| 112 | } | ||
| 113 | if (state->status.leds & (1u << USB_LED_CAPS_LOCK)) { | ||
| 114 | memcpy(output + pos, "CAPS ", 5); | ||
| 115 | pos += 5; | ||
| 116 | } | ||
| 117 | if (state->status.leds & (1u << USB_LED_SCROLL_LOCK)) { | ||
| 118 | memcpy(output + pos, "SCRL ", 5); | ||
| 119 | pos += 5; | ||
| 120 | } | ||
| 121 | if (state->status.leds & (1u << USB_LED_COMPOSE)) { | ||
| 122 | memcpy(output + pos, "COMP ", 5); | ||
| 123 | pos += 5; | ||
| 124 | } | ||
| 125 | if (state->status.leds & (1u << USB_LED_KANA)) { | ||
| 126 | memcpy(output + pos, "KANA", 4); | ||
| 127 | pos += 4; | ||
| 128 | } | ||
| 129 | output[pos] = 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 133 | (void)animation; | ||
| 134 | char output[LED_STATE_STRING_SIZE]; | ||
| 135 | get_led_state_string(output, state); | ||
| 136 | gdispClear(White); | ||
| 137 | gdispDrawString(0, 10, output, state->font_dejavusansbold12, Black); | ||
| 138 | return false; | ||
| 139 | } | ||
| 140 | |||
| 141 | bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 142 | (void)animation; | ||
| 143 | gdispClear(White); | ||
| 144 | uint8_t y = 10; | ||
| 145 | if (state->status.leds) { | ||
| 146 | char output[LED_STATE_STRING_SIZE]; | ||
| 147 | get_led_state_string(output, state); | ||
| 148 | gdispDrawString(0, 1, output, state->font_dejavusansbold12, Black); | ||
| 149 | y = 17; | ||
| 150 | } | ||
| 151 | gdispDrawString(0, y, state->layer_text, state->font_dejavusansbold12, Black); | ||
| 152 | return false; | ||
| 153 | } | ||
| 154 | |||
| 155 | bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 156 | (void)state; | ||
| 157 | (void)animation; | ||
| 158 | // Read the uGFX documentation for information how to use the displays | ||
| 159 | // http://wiki.ugfx.org/index.php/Main_Page | ||
| 160 | gdispClear(Black); | ||
| 161 | |||
| 162 | // You can use static variables for things that can't be found in the animation | ||
| 163 | // or state structs, here we use the image | ||
| 164 | |||
| 165 | // gdispGBlitArea is a tricky function to use since it supports blitting part of the image | ||
| 166 | // if you have full screen image, then just use LCD_WIDTH and LCD_HEIGHT for both source and target dimensions | ||
| 167 | gdispGBlitArea(GDISP, 0, 0, 128, 32, 0, 0, LCD_WIDTH, (pixel_t*)resource_lcd_logo); | ||
| 168 | |||
| 169 | return false; | ||
| 170 | } | ||
| 171 | |||
| 172 | bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 173 | (void)animation; | ||
| 174 | (void)state; | ||
| 175 | gdispSetPowerMode(powerOff); | ||
| 176 | return false; | ||
| 177 | } | ||
| 178 | |||
| 179 | bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 180 | (void)animation; | ||
| 181 | (void)state; | ||
| 182 | gdispSetPowerMode(powerOn); | ||
| 183 | return false; | ||
| 184 | } | ||
diff --git a/quantum/visualizer/lcd_keyframes.h b/quantum/visualizer/lcd_keyframes.h deleted file mode 100644 index b7125e832..000000000 --- a/quantum/visualizer/lcd_keyframes.h +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "visualizer.h" | ||
| 20 | |||
| 21 | // Displays the layer text centered vertically on the screen | ||
| 22 | bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 23 | // Displays a bitmap (0/1) of all the currently active layers | ||
| 24 | bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 25 | // Displays a bitmap (0/1) of all the currently active mods | ||
| 26 | bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 27 | // Displays the keyboard led states (CAPS (Caps lock), NUM (Num lock), SCRL (Scroll lock), COMP (Compose), KANA) | ||
| 28 | bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 29 | // Displays both the layer text and the led states | ||
| 30 | bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 31 | // Displays the QMK logo on the LCD screen | ||
| 32 | bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 33 | |||
| 34 | bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 35 | bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state); | ||
diff --git a/quantum/visualizer/led_backlight_keyframes.c b/quantum/visualizer/led_backlight_keyframes.c deleted file mode 100644 index 338ada522..000000000 --- a/quantum/visualizer/led_backlight_keyframes.c +++ /dev/null | |||
| @@ -1,143 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | #include "gfx.h" | ||
| 25 | #include <math.h> | ||
| 26 | #include "led_backlight_keyframes.h" | ||
| 27 | |||
| 28 | static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) { | ||
| 29 | int frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 30 | int current_pos = frame_length - animation->time_left_in_frame; | ||
| 31 | int delta = to - from; | ||
| 32 | int luma = (delta * current_pos) / frame_length; | ||
| 33 | luma += from; | ||
| 34 | return luma; | ||
| 35 | } | ||
| 36 | |||
| 37 | static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint8_t from, uint8_t to) { | ||
| 38 | uint8_t luma = fade_led_color(animation, from, to); | ||
| 39 | color_t color = LUMA2COLOR(luma); | ||
| 40 | gdispGClear(LED_DISPLAY, color); | ||
| 41 | } | ||
| 42 | |||
| 43 | // TODO: Should be customizable per keyboard | ||
| 44 | #define NUM_ROWS LED_HEIGHT | ||
| 45 | #define NUM_COLS LED_WIDTH | ||
| 46 | |||
| 47 | static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS]; | ||
| 48 | static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS]; | ||
| 49 | |||
| 50 | static uint8_t compute_gradient_color(float t, float index, float num) { | ||
| 51 | const float two_pi = M_PI * 2.0f; | ||
| 52 | float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi; | ||
| 53 | float x = t * two_pi + normalized_index; | ||
| 54 | float v = 0.5 * (cosf(x) + 1.0f); | ||
| 55 | return (uint8_t)(255.0f * v); | ||
| 56 | } | ||
| 57 | |||
| 58 | bool led_backlight_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 59 | (void)state; | ||
| 60 | keyframe_fade_all_leds_from_to(animation, 0, 255); | ||
| 61 | return true; | ||
| 62 | } | ||
| 63 | |||
| 64 | bool led_backlight_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 65 | (void)state; | ||
| 66 | keyframe_fade_all_leds_from_to(animation, 255, 0); | ||
| 67 | return true; | ||
| 68 | } | ||
| 69 | |||
| 70 | bool led_backlight_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 71 | (void)state; | ||
| 72 | float frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 73 | float current_pos = frame_length - animation->time_left_in_frame; | ||
| 74 | float t = current_pos / frame_length; | ||
| 75 | for (int i = 0; i < NUM_COLS; i++) { | ||
| 76 | uint8_t color = compute_gradient_color(t, i, NUM_COLS); | ||
| 77 | gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color)); | ||
| 78 | } | ||
| 79 | return true; | ||
| 80 | } | ||
| 81 | |||
| 82 | bool led_backlight_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 83 | (void)state; | ||
| 84 | float frame_length = animation->frame_lengths[animation->current_frame]; | ||
| 85 | float current_pos = frame_length - animation->time_left_in_frame; | ||
| 86 | float t = current_pos / frame_length; | ||
| 87 | for (int i = 0; i < NUM_ROWS; i++) { | ||
| 88 | uint8_t color = compute_gradient_color(t, i, NUM_ROWS); | ||
| 89 | gdispGDrawLine(LED_DISPLAY, 0, i, NUM_COLS - 1, i, LUMA2COLOR(color)); | ||
| 90 | } | ||
| 91 | return true; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void copy_current_led_state(uint8_t* dest) { | ||
| 95 | for (int i = 0; i < NUM_ROWS; i++) { | ||
| 96 | for (int j = 0; j < NUM_COLS; j++) { | ||
| 97 | dest[i * NUM_COLS + j] = gdispGGetPixelColor(LED_DISPLAY, j, i); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | bool led_backlight_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 102 | (void)state; | ||
| 103 | if (animation->first_update_of_frame) { | ||
| 104 | copy_current_led_state(&crossfade_start_frame[0][0]); | ||
| 105 | run_next_keyframe(animation, state); | ||
| 106 | copy_current_led_state(&crossfade_end_frame[0][0]); | ||
| 107 | } | ||
| 108 | for (int i = 0; i < NUM_ROWS; i++) { | ||
| 109 | for (int j = 0; j < NUM_COLS; j++) { | ||
| 110 | color_t color = LUMA2COLOR(fade_led_color(animation, crossfade_start_frame[i][j], crossfade_end_frame[i][j])); | ||
| 111 | gdispGDrawPixel(LED_DISPLAY, j, i, color); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | return true; | ||
| 115 | } | ||
| 116 | |||
| 117 | bool led_backlight_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 118 | (void)state; | ||
| 119 | (void)animation; | ||
| 120 | gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180); | ||
| 121 | return false; | ||
| 122 | } | ||
| 123 | |||
| 124 | bool led_backlight_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 125 | (void)state; | ||
| 126 | (void)animation; | ||
| 127 | gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0); | ||
| 128 | return false; | ||
| 129 | } | ||
| 130 | |||
| 131 | bool led_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 132 | (void)state; | ||
| 133 | (void)animation; | ||
| 134 | gdispGSetPowerMode(LED_DISPLAY, powerOff); | ||
| 135 | return false; | ||
| 136 | } | ||
| 137 | |||
| 138 | bool led_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 139 | (void)state; | ||
| 140 | (void)animation; | ||
| 141 | gdispGSetPowerMode(LED_DISPLAY, powerOn); | ||
| 142 | return false; | ||
| 143 | } | ||
diff --git a/quantum/visualizer/led_backlight_keyframes.h b/quantum/visualizer/led_backlight_keyframes.h deleted file mode 100644 index 90153be5e..000000000 --- a/quantum/visualizer/led_backlight_keyframes.h +++ /dev/null | |||
| @@ -1,40 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include "visualizer.h" | ||
| 28 | |||
| 29 | bool led_backlight_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 30 | bool led_backlight_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 31 | bool led_backlight_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 32 | bool led_backlight_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 33 | bool led_backlight_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 34 | bool led_backlight_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 35 | bool led_backlight_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 36 | |||
| 37 | bool led_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 38 | bool led_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 39 | |||
| 40 | extern keyframe_animation_t led_test_animation; | ||
diff --git a/quantum/visualizer/readme.md b/quantum/visualizer/readme.md deleted file mode 100644 index 298efb742..000000000 --- a/quantum/visualizer/readme.md +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | # A visualization library for the TMK keyboard firmware | ||
| 2 | |||
| 3 | This library is designed to work together with the [TMK keyboard firmware](https://github.com/tmk/tmk_keyboard). Currently it only works for [Chibios](http://www.chibios.org/) | ||
| 4 | flavors, but it would be possible to add support for other configurations as well. The LCD display functionality is provided by the [uGFX library](https://ugfx.io/). | ||
| 5 | |||
| 6 | ## To use this library as a user | ||
| 7 | You can and should modify the visualizer\_user.c file. Check the comments in the file for more information. | ||
| 8 | |||
| 9 | ## To add this library to custom keyboard projects | ||
| 10 | |||
| 11 | 1. Add tmk_visualizer as a submodule to your project | ||
| 12 | 1. Set VISUALIZER_DIR in the main keyboard project makefile to point to the submodule | ||
| 13 | 1. Define LCD\_ENABLE and/or LCD\_BACKLIGHT\_ENABLE, to enable support | ||
| 14 | 1. Include the visualizer.mk make file | ||
| 15 | 1. Copy the files in the example\_integration folder to your keyboard project | ||
| 16 | 1. All other files than the callback.c file are included automatically, so you will need to add callback.c to your makefile manually. If you already have a similar file in your project, you can just copy the functions instead of the whole file. | ||
| 17 | 1. Edit the files to match your hardware. You might might want to read the Chibios and UGfx documentation, for more information. | ||
| 18 | 1. If you enable LCD support you might also have to write a custom uGFX display driver, check the uGFX documentation for that. You probably also want to enable SPI support in your Chibios configuration. | ||
diff --git a/quantum/visualizer/resources/lcd_logo.c b/quantum/visualizer/resources/lcd_logo.c deleted file mode 100644 index 13bf734cb..000000000 --- a/quantum/visualizer/resources/lcd_logo.c +++ /dev/null | |||
| @@ -1,45 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "resources.h" | ||
| 18 | |||
| 19 | // clang-format off | ||
| 20 | |||
| 21 | // To generate an image array like this | ||
| 22 | // Ensure the image is 128 x 32 or smaller | ||
| 23 | // Convert the bitmap to a C array using a program like http://www.riuson.com/lcd-image-converter/ | ||
| 24 | // Ensure the the conversion process produces a monochrome format array - 1 bit/pixel, left to right, top to bottom | ||
| 25 | // Update array in the source code with the C array produced by the conversion program | ||
| 26 | |||
| 27 | // The image below is generated from lcd_logo.png | ||
| 28 | __attribute__((weak)) const uint8_t resource_lcd_logo[512] = { | ||
| 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 31 | 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 32 | 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 33 | 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 34 | 0x00, 0xFE, 0xEE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xEE, 0xF0, 0x01, 0xC6, 0x0D, 0x8C, 0x1F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 35 | 0x00, 0xFE, 0xEE, 0xFE, 0x03, 0xE7, 0x1D, 0x9C, 0x1F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xEE, 0xF0, 0x06, 0x37, 0x1D, 0xB8, 0x18, 0x0B, 0x59, 0xC8, 0x09, 0xE5, 0x9E, 0x00, | ||
| 36 | 0x00, 0x1E, 0xEE, 0xF0, 0x06, 0x37, 0xBD, 0xF0, 0x18, 0x6F, 0x7F, 0xEC, 0x9B, 0x37, 0xB3, 0x00, 0x00, 0xFE, 0xEE, 0xFE, 0x06, 0x37, 0xBD, 0xE0, 0x1F, 0x6C, 0x66, 0x6D, 0xD8, 0x36, 0x33, 0x00, | ||
| 37 | 0x00, 0x1E, 0xEE, 0xF0, 0x06, 0x36, 0xED, 0xF0, 0x1F, 0x6C, 0x66, 0x6D, 0x59, 0xF6, 0x3E, 0x00, 0x00, 0x1F, 0x6D, 0xF0, 0x06, 0x36, 0xED, 0xB8, 0x18, 0x6C, 0x66, 0x67, 0x73, 0x36, 0x30, 0x00, | ||
| 38 | 0x00, 0xFF, 0x83, 0xFE, 0x03, 0xE6, 0x4D, 0x9C, 0x18, 0x6C, 0x66, 0x67, 0x73, 0x36, 0x1F, 0x00, 0x00, 0x1F, 0xEF, 0xF0, 0x01, 0xC6, 0x0D, 0x8C, 0x18, 0x6C, 0x66, 0x62, 0x21, 0xD6, 0x0E, 0x00, | ||
| 39 | 0x00, 0xFF, 0xEF, 0xFE, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 40 | 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 41 | 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 42 | 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
| 45 | }; | ||
diff --git a/quantum/visualizer/resources/lcd_logo.png b/quantum/visualizer/resources/lcd_logo.png deleted file mode 100644 index 178ef65f1..000000000 --- a/quantum/visualizer/resources/lcd_logo.png +++ /dev/null | |||
| Binary files differ | |||
diff --git a/quantum/visualizer/resources/resources.h b/quantum/visualizer/resources/resources.h deleted file mode 100644 index 5178fbe55..000000000 --- a/quantum/visualizer/resources/resources.h +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | #ifdef LCD_ENABLE | ||
| 22 | extern const uint8_t resource_lcd_logo[]; | ||
| 23 | #endif | ||
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c deleted file mode 100644 index 709affbb7..000000000 --- a/quantum/visualizer/visualizer.c +++ /dev/null | |||
| @@ -1,483 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "config.h" | ||
| 26 | #include "visualizer.h" | ||
| 27 | #include <string.h> | ||
| 28 | #ifdef PROTOCOL_CHIBIOS | ||
| 29 | # include <ch.h> | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #include "gfx.h" | ||
| 33 | |||
| 34 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 35 | # include "lcd_backlight.h" | ||
| 36 | #endif | ||
| 37 | |||
| 38 | //#define DEBUG_VISUALIZER | ||
| 39 | |||
| 40 | #ifdef DEBUG_VISUALIZER | ||
| 41 | # include "debug.h" | ||
| 42 | #else | ||
| 43 | # include "nodebug.h" | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifdef SERIAL_LINK_ENABLE | ||
| 47 | # include "serial_link/protocol/transport.h" | ||
| 48 | # include "serial_link/system/serial_link.h" | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #include "action_util.h" | ||
| 52 | |||
| 53 | // Define this in config.h | ||
| 54 | #ifndef VISUALIZER_THREAD_PRIORITY | ||
| 55 | // The visualizer needs gfx thread priorities | ||
| 56 | # define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2) | ||
| 57 | #endif | ||
| 58 | |||
| 59 | static visualizer_keyboard_status_t current_status = {.layer = 0xFFFFFFFF, | ||
| 60 | .default_layer = 0xFFFFFFFF, | ||
| 61 | .leds = 0xFFFFFFFF, | ||
| 62 | #ifdef BACKLIGHT_ENABLE | ||
| 63 | .backlight_level = 0, | ||
| 64 | #endif | ||
| 65 | .mods = 0xFF, | ||
| 66 | .suspended = false, | ||
| 67 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 68 | .user_data = {0} | ||
| 69 | #endif | ||
| 70 | }; | ||
| 71 | |||
| 72 | static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) { | ||
| 73 | return status1->layer == status2->layer && status1->default_layer == status2->default_layer && status1->mods == status2->mods && status1->leds == status2->leds && status1->suspended == status2->suspended | ||
| 74 | #ifdef BACKLIGHT_ENABLE | ||
| 75 | && status1->backlight_level == status2->backlight_level | ||
| 76 | #endif | ||
| 77 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 78 | && memcmp(status1->user_data, status2->user_data, VISUALIZER_USER_DATA_SIZE) == 0 | ||
| 79 | #endif | ||
| 80 | ; | ||
| 81 | } | ||
| 82 | |||
| 83 | static bool visualizer_enabled = false; | ||
| 84 | |||
| 85 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 86 | static uint8_t user_data[VISUALIZER_USER_DATA_SIZE]; | ||
| 87 | #endif | ||
| 88 | |||
| 89 | #define MAX_SIMULTANEOUS_ANIMATIONS 4 | ||
| 90 | static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {}; | ||
| 91 | |||
| 92 | #ifdef SERIAL_LINK_ENABLE | ||
| 93 | MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t); | ||
| 94 | |||
| 95 | static remote_object_t* remote_objects[] = { | ||
| 96 | REMOTE_OBJECT(current_status), | ||
| 97 | }; | ||
| 98 | |||
| 99 | #endif | ||
| 100 | |||
| 101 | GDisplay* LCD_DISPLAY = 0; | ||
| 102 | GDisplay* LED_DISPLAY = 0; | ||
| 103 | |||
| 104 | #ifdef LCD_DISPLAY_NUMBER | ||
| 105 | __attribute__((weak)) GDisplay* get_lcd_display(void) { return gdispGetDisplay(LCD_DISPLAY_NUMBER); } | ||
| 106 | #endif | ||
| 107 | |||
| 108 | #ifdef LED_DISPLAY_NUMBER | ||
| 109 | __attribute__((weak)) GDisplay* get_led_display(void) { return gdispGetDisplay(LED_DISPLAY_NUMBER); } | ||
| 110 | #endif | ||
| 111 | |||
| 112 | void start_keyframe_animation(keyframe_animation_t* animation) { | ||
| 113 | animation->current_frame = -1; | ||
| 114 | animation->time_left_in_frame = 0; | ||
| 115 | animation->need_update = true; | ||
| 116 | int free_index = -1; | ||
| 117 | for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { | ||
| 118 | if (animations[i] == animation) { | ||
| 119 | return; | ||
| 120 | } | ||
| 121 | if (free_index == -1 && animations[i] == NULL) { | ||
| 122 | free_index = i; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | if (free_index != -1) { | ||
| 126 | animations[free_index] = animation; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | void stop_keyframe_animation(keyframe_animation_t* animation) { | ||
| 131 | animation->current_frame = animation->num_frames; | ||
| 132 | animation->time_left_in_frame = 0; | ||
| 133 | animation->need_update = true; | ||
| 134 | animation->first_update_of_frame = false; | ||
| 135 | animation->last_update_of_frame = false; | ||
| 136 | for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { | ||
| 137 | if (animations[i] == animation) { | ||
| 138 | animations[i] = NULL; | ||
| 139 | return; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | void stop_all_keyframe_animations(void) { | ||
| 145 | for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { | ||
| 146 | if (animations[i]) { | ||
| 147 | animations[i]->current_frame = animations[i]->num_frames; | ||
| 148 | animations[i]->time_left_in_frame = 0; | ||
| 149 | animations[i]->need_update = true; | ||
| 150 | animations[i]->first_update_of_frame = false; | ||
| 151 | animations[i]->last_update_of_frame = false; | ||
| 152 | animations[i] = NULL; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | static uint8_t get_num_running_animations(void) { | ||
| 158 | uint8_t count = 0; | ||
| 159 | for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { | ||
| 160 | count += animations[i] ? 1 : 0; | ||
| 161 | } | ||
| 162 | return count; | ||
| 163 | } | ||
| 164 | |||
| 165 | static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) { | ||
| 166 | // TODO: Clean up this messy code | ||
| 167 | dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame, animation->time_left_in_frame, delta); | ||
| 168 | if (animation->current_frame == animation->num_frames) { | ||
| 169 | animation->need_update = false; | ||
| 170 | return false; | ||
| 171 | } | ||
| 172 | if (animation->current_frame == -1) { | ||
| 173 | animation->current_frame = 0; | ||
| 174 | animation->time_left_in_frame = animation->frame_lengths[0]; | ||
| 175 | animation->need_update = true; | ||
| 176 | animation->first_update_of_frame = true; | ||
| 177 | } else { | ||
| 178 | animation->time_left_in_frame -= delta; | ||
| 179 | while (animation->time_left_in_frame <= 0) { | ||
| 180 | int left = animation->time_left_in_frame; | ||
| 181 | if (animation->need_update) { | ||
| 182 | animation->time_left_in_frame = 0; | ||
| 183 | animation->last_update_of_frame = true; | ||
| 184 | (*animation->frame_functions[animation->current_frame])(animation, state); | ||
| 185 | animation->last_update_of_frame = false; | ||
| 186 | } | ||
| 187 | animation->current_frame++; | ||
| 188 | animation->need_update = true; | ||
| 189 | animation->first_update_of_frame = true; | ||
| 190 | if (animation->current_frame == animation->num_frames) { | ||
| 191 | if (animation->loop) { | ||
| 192 | animation->current_frame = 0; | ||
| 193 | } else { | ||
| 194 | stop_keyframe_animation(animation); | ||
| 195 | return false; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | delta = -left; | ||
| 199 | animation->time_left_in_frame = animation->frame_lengths[animation->current_frame]; | ||
| 200 | animation->time_left_in_frame -= delta; | ||
| 201 | } | ||
| 202 | } | ||
| 203 | if (animation->need_update) { | ||
| 204 | animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state); | ||
| 205 | animation->first_update_of_frame = false; | ||
| 206 | } | ||
| 207 | |||
| 208 | systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame; | ||
| 209 | if (wanted_sleep < *sleep_time) { | ||
| 210 | *sleep_time = wanted_sleep; | ||
| 211 | } | ||
| 212 | |||
| 213 | return true; | ||
| 214 | } | ||
| 215 | |||
| 216 | void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 217 | int next_frame = animation->current_frame + 1; | ||
| 218 | if (next_frame == animation->num_frames) { | ||
| 219 | next_frame = 0; | ||
| 220 | } | ||
| 221 | keyframe_animation_t temp_animation = *animation; | ||
| 222 | temp_animation.current_frame = next_frame; | ||
| 223 | temp_animation.time_left_in_frame = animation->frame_lengths[next_frame]; | ||
| 224 | temp_animation.first_update_of_frame = true; | ||
| 225 | temp_animation.last_update_of_frame = false; | ||
| 226 | temp_animation.need_update = false; | ||
| 227 | visualizer_state_t temp_state = *state; | ||
| 228 | (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state); | ||
| 229 | } | ||
| 230 | |||
| 231 | // TODO: Optimize the stack size, this is probably way too big | ||
| 232 | static DECLARE_THREAD_STACK(visualizerThreadStack, 1024); | ||
| 233 | static DECLARE_THREAD_FUNCTION(visualizerThread, arg) { | ||
| 234 | (void)arg; | ||
| 235 | |||
| 236 | GListener event_listener; | ||
| 237 | geventListenerInit(&event_listener); | ||
| 238 | geventAttachSource(&event_listener, (GSourceHandle)¤t_status, 0); | ||
| 239 | |||
| 240 | visualizer_keyboard_status_t initial_status = { | ||
| 241 | .default_layer = 0xFFFFFFFF, | ||
| 242 | .layer = 0xFFFFFFFF, | ||
| 243 | .mods = 0xFF, | ||
| 244 | .leds = 0xFFFFFFFF, | ||
| 245 | .suspended = false, | ||
| 246 | #ifdef BACKLIGHT_ENABLE | ||
| 247 | .backlight_level = 0, | ||
| 248 | #endif | ||
| 249 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 250 | .user_data = {0}, | ||
| 251 | #endif | ||
| 252 | }; | ||
| 253 | |||
| 254 | visualizer_state_t state = {.status = initial_status, | ||
| 255 | .current_lcd_color = 0, | ||
| 256 | #ifdef LCD_ENABLE | ||
| 257 | .font_fixed5x8 = gdispOpenFont("fixed_5x8"), | ||
| 258 | .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12") | ||
| 259 | #endif | ||
| 260 | }; | ||
| 261 | initialize_user_visualizer(&state); | ||
| 262 | state.prev_lcd_color = state.current_lcd_color; | ||
| 263 | |||
| 264 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 265 | lcd_backlight_color(LCD_HUE(state.current_lcd_color), LCD_SAT(state.current_lcd_color), LCD_INT(state.current_lcd_color)); | ||
| 266 | #endif | ||
| 267 | |||
| 268 | systemticks_t sleep_time = TIME_INFINITE; | ||
| 269 | systemticks_t current_time = gfxSystemTicks(); | ||
| 270 | bool force_update = true; | ||
| 271 | |||
| 272 | while (true) { | ||
| 273 | systemticks_t new_time = gfxSystemTicks(); | ||
| 274 | systemticks_t delta = new_time - current_time; | ||
| 275 | current_time = new_time; | ||
| 276 | bool enabled = visualizer_enabled; | ||
| 277 | if (force_update || !same_status(&state.status, ¤t_status)) { | ||
| 278 | force_update = false; | ||
| 279 | #if BACKLIGHT_ENABLE | ||
| 280 | if (current_status.backlight_level != state.status.backlight_level) { | ||
| 281 | if (current_status.backlight_level != 0) { | ||
| 282 | gdispGSetPowerMode(LED_DISPLAY, powerOn); | ||
| 283 | uint16_t percent = (uint16_t)current_status.backlight_level * 100 / BACKLIGHT_LEVELS; | ||
| 284 | gdispGSetBacklight(LED_DISPLAY, percent); | ||
| 285 | } else { | ||
| 286 | gdispGSetPowerMode(LED_DISPLAY, powerOff); | ||
| 287 | } | ||
| 288 | state.status.backlight_level = current_status.backlight_level; | ||
| 289 | } | ||
| 290 | #endif | ||
| 291 | if (visualizer_enabled) { | ||
| 292 | if (current_status.suspended) { | ||
| 293 | stop_all_keyframe_animations(); | ||
| 294 | visualizer_enabled = false; | ||
| 295 | state.status = current_status; | ||
| 296 | user_visualizer_suspend(&state); | ||
| 297 | } else { | ||
| 298 | visualizer_keyboard_status_t prev_status = state.status; | ||
| 299 | state.status = current_status; | ||
| 300 | update_user_visualizer_state(&state, &prev_status); | ||
| 301 | } | ||
| 302 | state.prev_lcd_color = state.current_lcd_color; | ||
| 303 | } | ||
| 304 | } | ||
| 305 | if (!enabled && state.status.suspended && current_status.suspended == false) { | ||
| 306 | // Setting the status to the initial status will force an update | ||
| 307 | // when the visualizer is enabled again | ||
| 308 | state.status = initial_status; | ||
| 309 | state.status.suspended = false; | ||
| 310 | stop_all_keyframe_animations(); | ||
| 311 | user_visualizer_resume(&state); | ||
| 312 | state.prev_lcd_color = state.current_lcd_color; | ||
| 313 | } | ||
| 314 | sleep_time = TIME_INFINITE; | ||
| 315 | for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { | ||
| 316 | if (animations[i]) { | ||
| 317 | update_keyframe_animation(animations[i], &state, delta, &sleep_time); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | #ifdef BACKLIGHT_ENABLE | ||
| 321 | gdispGFlush(LED_DISPLAY); | ||
| 322 | #endif | ||
| 323 | |||
| 324 | #ifdef LCD_ENABLE | ||
| 325 | gdispGFlush(LCD_DISPLAY); | ||
| 326 | #endif | ||
| 327 | |||
| 328 | #ifdef EMULATOR | ||
| 329 | draw_emulator(); | ||
| 330 | #endif | ||
| 331 | // Enable the visualizer when the startup or the suspend animation has finished | ||
| 332 | if (!visualizer_enabled && state.status.suspended == false && get_num_running_animations() == 0) { | ||
| 333 | visualizer_enabled = true; | ||
| 334 | force_update = true; | ||
| 335 | sleep_time = 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | systemticks_t after_update = gfxSystemTicks(); | ||
| 339 | unsigned update_delta = after_update - current_time; | ||
| 340 | if (sleep_time != TIME_INFINITE) { | ||
| 341 | if (sleep_time > update_delta) { | ||
| 342 | sleep_time -= update_delta; | ||
| 343 | } else { | ||
| 344 | sleep_time = 0; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time); | ||
| 348 | #ifdef PROTOCOL_CHIBIOS | ||
| 349 | // The gEventWait function really takes milliseconds, even if the documentation says ticks. | ||
| 350 | // Unfortunately there's no generic ugfx conversion from system time to milliseconds, | ||
| 351 | // so let's do it in a platform dependent way. | ||
| 352 | |||
| 353 | // On windows the system ticks is the same as milliseconds anyway | ||
| 354 | if (sleep_time != TIME_INFINITE) { | ||
| 355 | sleep_time = TIME_I2MS(sleep_time); | ||
| 356 | } | ||
| 357 | #endif | ||
| 358 | geventEventWait(&event_listener, sleep_time); | ||
| 359 | } | ||
| 360 | #ifdef LCD_ENABLE | ||
| 361 | gdispCloseFont(state.font_fixed5x8); | ||
| 362 | gdispCloseFont(state.font_dejavusansbold12); | ||
| 363 | #endif | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | void visualizer_init(void) { | ||
| 369 | gfxInit(); | ||
| 370 | |||
| 371 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 372 | lcd_backlight_init(); | ||
| 373 | #endif | ||
| 374 | |||
| 375 | #ifdef SERIAL_LINK_ENABLE | ||
| 376 | add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*)); | ||
| 377 | #endif | ||
| 378 | |||
| 379 | #ifdef LCD_ENABLE | ||
| 380 | LCD_DISPLAY = get_lcd_display(); | ||
| 381 | #endif | ||
| 382 | |||
| 383 | #ifdef BACKLIGHT_ENABLE | ||
| 384 | LED_DISPLAY = get_led_display(); | ||
| 385 | #endif | ||
| 386 | |||
| 387 | // We are using a low priority thread, the idea is to have it run only | ||
| 388 | // when the main thread is sleeping during the matrix scanning | ||
| 389 | gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack), VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL); | ||
| 390 | } | ||
| 391 | |||
| 392 | void update_status(bool changed) { | ||
| 393 | if (changed) { | ||
| 394 | GSourceListener* listener = geventGetSourceListener((GSourceHandle)¤t_status, NULL); | ||
| 395 | if (listener) { | ||
| 396 | geventSendEvent(listener); | ||
| 397 | } | ||
| 398 | } | ||
| 399 | #ifdef SERIAL_LINK_ENABLE | ||
| 400 | static systime_t last_update = 0; | ||
| 401 | systime_t current_update = chVTGetSystemTimeX(); | ||
| 402 | systime_t delta = current_update - last_update; | ||
| 403 | if (changed || delta > TIME_MS2I(10)) { | ||
| 404 | last_update = current_update; | ||
| 405 | visualizer_keyboard_status_t* r = begin_write_current_status(); | ||
| 406 | *r = current_status; | ||
| 407 | end_write_current_status(); | ||
| 408 | } | ||
| 409 | #endif | ||
| 410 | } | ||
| 411 | |||
| 412 | uint8_t visualizer_get_mods() { | ||
| 413 | uint8_t mods = get_mods(); | ||
| 414 | |||
| 415 | #ifndef NO_ACTION_ONESHOT | ||
| 416 | if (!has_oneshot_mods_timed_out()) { | ||
| 417 | mods |= get_oneshot_mods(); | ||
| 418 | } | ||
| 419 | #endif | ||
| 420 | return mods; | ||
| 421 | } | ||
| 422 | |||
| 423 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 424 | void visualizer_set_user_data(void* u) { memcpy(user_data, u, VISUALIZER_USER_DATA_SIZE); } | ||
| 425 | #endif | ||
| 426 | |||
| 427 | void visualizer_update(layer_state_t default_state, layer_state_t state, uint8_t mods, uint32_t leds) { | ||
| 428 | // Note that there's a small race condition here, the thread could read | ||
| 429 | // a state where one of these are set but not the other. But this should | ||
| 430 | // not really matter as it will be fixed during the next loop step. | ||
| 431 | // Alternatively a mutex could be used instead of the volatile variables | ||
| 432 | |||
| 433 | bool changed = false; | ||
| 434 | #ifdef SERIAL_LINK_ENABLE | ||
| 435 | if (is_serial_link_connected()) { | ||
| 436 | visualizer_keyboard_status_t* new_status = read_current_status(); | ||
| 437 | if (new_status) { | ||
| 438 | if (!same_status(¤t_status, new_status)) { | ||
| 439 | changed = true; | ||
| 440 | current_status = *new_status; | ||
| 441 | } | ||
| 442 | } | ||
| 443 | } else { | ||
| 444 | #else | ||
| 445 | { | ||
| 446 | #endif | ||
| 447 | visualizer_keyboard_status_t new_status = { | ||
| 448 | .layer = state, | ||
| 449 | .default_layer = default_state, | ||
| 450 | .mods = mods, | ||
| 451 | .leds = leds, | ||
| 452 | #ifdef BACKLIGHT_ENABLE | ||
| 453 | .backlight_level = current_status.backlight_level, | ||
| 454 | #endif | ||
| 455 | .suspended = current_status.suspended, | ||
| 456 | }; | ||
| 457 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 458 | memcpy(new_status.user_data, user_data, VISUALIZER_USER_DATA_SIZE); | ||
| 459 | #endif | ||
| 460 | if (!same_status(¤t_status, &new_status)) { | ||
| 461 | changed = true; | ||
| 462 | current_status = new_status; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | update_status(changed); | ||
| 466 | } | ||
| 467 | |||
| 468 | void visualizer_suspend(void) { | ||
| 469 | current_status.suspended = true; | ||
| 470 | update_status(true); | ||
| 471 | } | ||
| 472 | |||
| 473 | void visualizer_resume(void) { | ||
| 474 | current_status.suspended = false; | ||
| 475 | update_status(true); | ||
| 476 | } | ||
| 477 | |||
| 478 | #ifdef BACKLIGHT_ENABLE | ||
| 479 | void backlight_set(uint8_t level) { | ||
| 480 | current_status.backlight_level = level; | ||
| 481 | update_status(true); | ||
| 482 | } | ||
| 483 | #endif | ||
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h deleted file mode 100644 index 627c80a30..000000000 --- a/quantum/visualizer/visualizer.h +++ /dev/null | |||
| @@ -1,154 +0,0 @@ | |||
| 1 | /* | ||
| 2 | The MIT License (MIT) | ||
| 3 | |||
| 4 | Copyright (c) 2016 Fred Sundvik | ||
| 5 | |||
| 6 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | of this software and associated documentation files (the "Software"), to deal | ||
| 8 | in the Software without restriction, including without limitation the rights | ||
| 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 10 | copies of the Software, and to permit persons to whom the Software is | ||
| 11 | furnished to do so, subject to the following conditions: | ||
| 12 | |||
| 13 | The above copyright notice and this permission notice shall be included in all | ||
| 14 | copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 22 | SOFTWARE. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | |||
| 27 | #include <stdlib.h> | ||
| 28 | #include <stdint.h> | ||
| 29 | #include <stdbool.h> | ||
| 30 | |||
| 31 | #include "config.h" | ||
| 32 | #include "gfx.h" | ||
| 33 | #include "action_layer.h" | ||
| 34 | |||
| 35 | #ifdef LCD_BACKLIGHT_ENABLE | ||
| 36 | # include "lcd_backlight.h" | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #ifdef BACKLIGHT_ENABLE | ||
| 40 | # include "backlight.h" | ||
| 41 | #endif | ||
| 42 | |||
| 43 | // use this function to merge both real_mods and oneshot_mods in a uint16_t | ||
| 44 | uint8_t visualizer_get_mods(void); | ||
| 45 | |||
| 46 | // This need to be called once at the start | ||
| 47 | void visualizer_init(void); | ||
| 48 | // This should be called at every matrix scan | ||
| 49 | void visualizer_update(layer_state_t default_state, layer_state_t state, uint8_t mods, uint32_t leds); | ||
| 50 | |||
| 51 | // This should be called when the keyboard goes to suspend state | ||
| 52 | void visualizer_suspend(void); | ||
| 53 | // This should be called when the keyboard wakes up from suspend state | ||
| 54 | void visualizer_resume(void); | ||
| 55 | |||
| 56 | // These functions are week, so they can be overridden by the keyboard | ||
| 57 | // if needed | ||
| 58 | GDisplay* get_lcd_display(void); | ||
| 59 | GDisplay* get_led_display(void); | ||
| 60 | |||
| 61 | // For emulator builds, this function need to be implemented | ||
| 62 | #ifdef EMULATOR | ||
| 63 | void draw_emulator(void); | ||
| 64 | #endif | ||
| 65 | |||
| 66 | // If you need support for more than 16 keyframes per animation, you can change this | ||
| 67 | #define MAX_VISUALIZER_KEY_FRAMES 16 | ||
| 68 | |||
| 69 | struct keyframe_animation_t; | ||
| 70 | |||
| 71 | typedef struct { | ||
| 72 | layer_state_t layer; | ||
| 73 | layer_state_t default_layer; | ||
| 74 | uint32_t leds; // See led.h for available statuses | ||
| 75 | uint8_t mods; | ||
| 76 | bool suspended; | ||
| 77 | #ifdef BACKLIGHT_ENABLE | ||
| 78 | uint8_t backlight_level; | ||
| 79 | #endif | ||
| 80 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 81 | uint8_t user_data[VISUALIZER_USER_DATA_SIZE]; | ||
| 82 | #endif | ||
| 83 | } visualizer_keyboard_status_t; | ||
| 84 | |||
| 85 | // The state struct is used by the various keyframe functions | ||
| 86 | // It's also used for setting the LCD color and layer text | ||
| 87 | // from the user customized code | ||
| 88 | typedef struct visualizer_state_t { | ||
| 89 | // The user code should primarily be modifying these | ||
| 90 | uint32_t target_lcd_color; | ||
| 91 | const char* layer_text; | ||
| 92 | |||
| 93 | // The user visualizer(and animation functions) can read these | ||
| 94 | visualizer_keyboard_status_t status; | ||
| 95 | |||
| 96 | // These are used by the animation functions | ||
| 97 | uint32_t current_lcd_color; | ||
| 98 | uint32_t prev_lcd_color; | ||
| 99 | #ifdef LCD_ENABLE | ||
| 100 | gFont font_fixed5x8; | ||
| 101 | gFont font_dejavusansbold12; | ||
| 102 | #endif | ||
| 103 | } visualizer_state_t; | ||
| 104 | |||
| 105 | // Any custom keyframe function should have this signature | ||
| 106 | // return true to get continuous updates, otherwise you will only get one | ||
| 107 | // update per frame | ||
| 108 | typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*); | ||
| 109 | |||
| 110 | // Represents a keyframe animation, so fields are internal to the system | ||
| 111 | // while others are meant to be initialized by the user code | ||
| 112 | typedef struct keyframe_animation_t { | ||
| 113 | // These should be initialized | ||
| 114 | int num_frames; | ||
| 115 | bool loop; | ||
| 116 | int frame_lengths[MAX_VISUALIZER_KEY_FRAMES]; | ||
| 117 | frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES]; | ||
| 118 | |||
| 119 | // Used internally by the system, and can also be read by | ||
| 120 | // keyframe update functions | ||
| 121 | int current_frame; | ||
| 122 | int time_left_in_frame; | ||
| 123 | bool first_update_of_frame; | ||
| 124 | bool last_update_of_frame; | ||
| 125 | bool need_update; | ||
| 126 | |||
| 127 | } keyframe_animation_t; | ||
| 128 | |||
| 129 | extern GDisplay* LCD_DISPLAY; | ||
| 130 | extern GDisplay* LED_DISPLAY; | ||
| 131 | |||
| 132 | void start_keyframe_animation(keyframe_animation_t* animation); | ||
| 133 | void stop_keyframe_animation(keyframe_animation_t* animation); | ||
| 134 | // This runs the next keyframe, but does not update the animation state | ||
| 135 | // Useful for crossfades for example | ||
| 136 | void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state); | ||
| 137 | |||
| 138 | // The master can set userdata which will be transferred to the slave | ||
| 139 | #ifdef VISUALIZER_USER_DATA_SIZE | ||
| 140 | void visualizer_set_user_data(void* user_data); | ||
| 141 | #endif | ||
| 142 | |||
| 143 | // These functions have to be implemented by the user | ||
| 144 | // Called regularly each time the state has changed (but not every scan loop) | ||
| 145 | void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status); | ||
| 146 | // Called when the computer goes to suspend, will also stop calling update_user_visualizer_state | ||
| 147 | void user_visualizer_suspend(visualizer_state_t* state); | ||
| 148 | // You have to start at least one animation as a response to the following two functions | ||
| 149 | // When the animation has finished the visualizer will resume normal operation and start calling the | ||
| 150 | // update_user_visualizer_state again | ||
| 151 | // Called when the keyboard boots up | ||
| 152 | void initialize_user_visualizer(visualizer_state_t* state); | ||
| 153 | // Called when the computer resumes from a suspend | ||
| 154 | void user_visualizer_resume(visualizer_state_t* state); | ||
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk deleted file mode 100644 index 4c961ac59..000000000 --- a/quantum/visualizer/visualizer.mk +++ /dev/null | |||
| @@ -1,123 +0,0 @@ | |||
| 1 | # The MIT License (MIT) | ||
| 2 | # | ||
| 3 | # Copyright (c) 2016 Fred Sundvik | ||
| 4 | # | ||
| 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | # of this software and associated documentation files (the "Software"), to deal | ||
| 7 | # in the Software without restriction, including without limitation the rights | ||
| 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | # copies of the Software, and to permit persons to whom the Software is | ||
| 10 | # furnished to do so, subject to the following conditions: | ||
| 11 | # | ||
| 12 | # The above copyright notice and this permission notice shall be included in all | ||
| 13 | # copies or substantial portions of the Software. | ||
| 14 | # | ||
| 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | # SOFTWARE. | ||
| 22 | |||
| 23 | define ADD_DRIVER | ||
| 24 | $(1)_DRIVER:=$(strip $($(1)_DRIVER)) | ||
| 25 | $(1)_WIDTH:=$(strip $($(1)_WIDTH)) | ||
| 26 | $(1)_HEIGHT:=$(strip $($(1)_HEIGHT)) | ||
| 27 | ifeq ($($(1)_DRIVER),) | ||
| 28 | $$(error $(1)_DRIVER is not defined) | ||
| 29 | endif | ||
| 30 | ifeq ($($(1)_WIDTH),) | ||
| 31 | $$(error $(1)_WIDTH is not defined) | ||
| 32 | endif | ||
| 33 | ifeq ($($(1)_HEIGHT),) | ||
| 34 | $$(error $(1)_HEIGHT is not defined) | ||
| 35 | endif | ||
| 36 | OPT_DEFS+=-D$(1)_WIDTH=$($(1)_WIDTH) | ||
| 37 | OPT_DEFS+=-D$(1)_HEIGHT=$($(1)_HEIGHT) | ||
| 38 | GFXDEFS+=-D$(1)_WIDTH=$($(1)_WIDTH) | ||
| 39 | GFXDEFS+=-D$(1)_HEIGHT=$($(1)_HEIGHT) | ||
| 40 | $(1)_DISPLAY_NUMBER:=$$(words $$(GDISP_DRIVER_LIST)) | ||
| 41 | OPT_DEFS+=-D$(1)_DISPLAY_NUMBER=$$($(1)_DISPLAY_NUMBER) | ||
| 42 | include $(TOP_DIR)/drivers/ugfx/gdisp/$($(1)_DRIVER)/driver.mk | ||
| 43 | endef | ||
| 44 | |||
| 45 | GDISP_DRIVER_LIST:= | ||
| 46 | |||
| 47 | SRC += $(VISUALIZER_DIR)/visualizer.c \ | ||
| 48 | $(VISUALIZER_DIR)/visualizer_keyframes.c | ||
| 49 | EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR) | ||
| 50 | GFXLIB = $(LIB_PATH)/ugfx | ||
| 51 | VPATH += $(VISUALIZER_PATH) | ||
| 52 | |||
| 53 | OPT_DEFS += -DVISUALIZER_ENABLE | ||
| 54 | |||
| 55 | ifdef LCD_ENABLE | ||
| 56 | OPT_DEFS += -DLCD_ENABLE | ||
| 57 | ULIBS += -lm | ||
| 58 | endif | ||
| 59 | |||
| 60 | ifeq ($(strip $(LCD_ENABLE)), yes) | ||
| 61 | SRC += $(VISUALIZER_DIR)/lcd_keyframes.c | ||
| 62 | ifeq ($(strip $(LCD_BACKLIGHT_ENABLE)), yes) | ||
| 63 | OPT_DEFS += -DLCD_BACKLIGHT_ENABLE | ||
| 64 | SRC += $(VISUALIZER_DIR)/lcd_backlight.c | ||
| 65 | SRC += $(VISUALIZER_DIR)/lcd_backlight_keyframes.c | ||
| 66 | endif | ||
| 67 | # Note, that the linker will strip out any resources that are not actually in use | ||
| 68 | SRC += $(VISUALIZER_DIR)/resources/lcd_logo.c | ||
| 69 | $(eval $(call ADD_DRIVER,LCD)) | ||
| 70 | endif | ||
| 71 | |||
| 72 | ifeq ($(strip $(BACKLIGHT_ENABLE)), yes) | ||
| 73 | SRC += $(VISUALIZER_DIR)/led_backlight_keyframes.c | ||
| 74 | $(eval $(call ADD_DRIVER,LED)) | ||
| 75 | endif | ||
| 76 | |||
| 77 | SRC += $(VISUALIZER_DIR)/default_animations.c | ||
| 78 | |||
| 79 | include $(GFXLIB)/gfx.mk | ||
| 80 | # For the common_gfxconf.h | ||
| 81 | GFXINC += quantum/visualizer | ||
| 82 | |||
| 83 | GFXSRC := $(patsubst $(TOP_DIR)/%,%,$(GFXSRC)) | ||
| 84 | GFXDEFS := $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS))) | ||
| 85 | |||
| 86 | GDISP_LIST_COMMA=, | ||
| 87 | GDISP_LIST_EMPTY= | ||
| 88 | GDISP_LIST_SPACE=$(GDISP_LIST_EMPTY) $(GDISP_LIST_EMPTY) | ||
| 89 | |||
| 90 | GDISP_DRIVER_LIST := $(strip $(GDISP_DRIVER_LIST)) | ||
| 91 | GDISP_DRIVER_LIST := $(subst $(GDISP_LIST_SPACE),$(GDISP_LIST_COMMA),$(GDISP_DRIVER_LIST)) | ||
| 92 | |||
| 93 | GFXDEFS +=-DGDISP_DRIVER_LIST="$(GDISP_DRIVER_LIST)" | ||
| 94 | |||
| 95 | ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","") | ||
| 96 | SRC += $(KEYMAP_PATH)/visualizer.c | ||
| 97 | else | ||
| 98 | VISUALIZER_1 := $(KEYBOARD_PATH_1)/visualizer.c | ||
| 99 | VISUALIZER_2 := $(KEYBOARD_PATH_2)/visualizer.c | ||
| 100 | VISUALIZER_3 := $(KEYBOARD_PATH_3)/visualizer.c | ||
| 101 | VISUALIZER_4 := $(KEYBOARD_PATH_4)/visualizer.c | ||
| 102 | VISUALIZER_5 := $(KEYBOARD_PATH_5)/visualizer.c | ||
| 103 | |||
| 104 | ifneq ("$(wildcard $(VISUALIZER_5))","") | ||
| 105 | SRC += $(VISUALIZER_5) | ||
| 106 | endif | ||
| 107 | ifneq ("$(wildcard $(VISUALIZER_4))","") | ||
| 108 | SRC += $(VISUALIZER_4) | ||
| 109 | endif | ||
| 110 | ifneq ("$(wildcard $(VISUALIZER_3))","") | ||
| 111 | SRC += $(VISUALIZER_3) | ||
| 112 | endif | ||
| 113 | ifneq ("$(wildcard $(VISUALIZER_2))","") | ||
| 114 | SRC += $(VISUALIZER_2) | ||
| 115 | endif | ||
| 116 | ifneq ("$(wildcard $(VISUALIZER_1))","") | ||
| 117 | SRC += $(VISUALIZER_1) | ||
| 118 | endif | ||
| 119 | endif | ||
| 120 | |||
| 121 | ifdef EMULATOR | ||
| 122 | UINCDIR += $(TMK_DIR)/common | ||
| 123 | endif | ||
diff --git a/quantum/visualizer/visualizer_keyframes.c b/quantum/visualizer/visualizer_keyframes.c deleted file mode 100644 index 8f6a7e15a..000000000 --- a/quantum/visualizer/visualizer_keyframes.c +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include "visualizer_keyframes.h" | ||
| 18 | |||
| 19 | bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) { | ||
| 20 | (void)animation; | ||
| 21 | (void)state; | ||
| 22 | return false; | ||
| 23 | } | ||
diff --git a/quantum/visualizer/visualizer_keyframes.h b/quantum/visualizer/visualizer_keyframes.h deleted file mode 100644 index c92ff1611..000000000 --- a/quantum/visualizer/visualizer_keyframes.h +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | /* Copyright 2017 Fred Sundvik | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "visualizer.h" | ||
| 20 | |||
| 21 | // Some predefined keyframe functions that can be used by the user code | ||
| 22 | // Does nothing, useful for adding delays | ||
| 23 | bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state); | ||
