diff options
author | Callum Oakley <c.oakley108@gmail.com> | 2016-09-01 17:55:00 +0100 |
---|---|---|
committer | Callum Oakley <c.oakley108@gmail.com> | 2016-09-01 17:55:00 +0100 |
commit | 9c3193f22555119eb15f63f5ae5efe45e6d7358c (patch) | |
tree | a0dcfb3ed442c12a66b444c4c579711660c30657 /quantum | |
parent | 993d72b11fca8d50296570dc85e9354f8045c4a6 (diff) | |
parent | e28d151a8a1d458f3c18897c6095decc17b0c3a1 (diff) |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'quantum')
25 files changed, 1350 insertions, 834 deletions
diff --git a/quantum/config_common.h b/quantum/config_common.h index 09a4fe7010..8ed5f4a106 100644 --- a/quantum/config_common.h +++ b/quantum/config_common.h @@ -45,6 +45,15 @@ #define F5 0xF5 #define F6 0xF6 #define F7 0xF7 +#define A0 0x00 +#define A1 0x01 +#define A2 0x02 +#define A3 0x03 +#define A4 0x04 +#define A5 0x05 +#define A6 0x06 +#define A7 0x07 + /* USART configuration */ #ifdef BLUETOOTH_ENABLE diff --git a/quantum/dynamic_macro.h b/quantum/dynamic_macro.h new file mode 100644 index 0000000000..a3ad61bc7e --- /dev/null +++ b/quantum/dynamic_macro.h @@ -0,0 +1,226 @@ +/* Author: Wojciech Siewierski < wojciech dot siewierski at onet dot pl > */ +#ifndef DYNAMIC_MACROS_H +#define DYNAMIC_MACROS_H + +#include "action_layer.h" + +#ifndef DYNAMIC_MACRO_SIZE +/* May be overridden with a custom value. Be aware that the effective + * macro length is half of this value: each keypress is recorded twice + * because of the down-event and up-event. This is not a bug, it's the + * intended behavior. */ +#define DYNAMIC_MACRO_SIZE 256 +#endif + +/* DYNAMIC_MACRO_RANGE must be set as the last element of user's + * "planck_keycodes" enum prior to including this header. This allows + * us to 'extend' it. + */ +enum dynamic_macro_keycodes { + DYN_REC_START1 = DYNAMIC_MACRO_RANGE, + DYN_REC_START2, + DYN_MACRO_PLAY1, + DYN_MACRO_PLAY2, +}; + +/* Blink the LEDs to notify the user about some event. */ +void dynamic_macro_led_blink(void) +{ + backlight_toggle(); + _delay_ms(100); + backlight_toggle(); +} + +/** + * Start recording of the dynamic macro. + * + * @param[out] macro_pointer The new macro buffer iterator. + * @param[in] macro_buffer The macro buffer used to initialize macro_pointer. + */ +void dynamic_macro_record_start( + keyrecord_t **macro_pointer, keyrecord_t *macro_buffer) +{ + dynamic_macro_led_blink(); + + clear_keyboard(); + layer_clear(); + *macro_pointer = macro_buffer; +} + +/** + * Play the dynamic macro. + * + * @param macro_buffer[in] The beginning of the macro buffer being played. + * @param macro_end[in] The element after the last macro buffer element. + * @param direction[in] Either +1 or -1, which way to iterate the buffer. + */ +void dynamic_macro_play( + keyrecord_t *macro_buffer, keyrecord_t *macro_end, int8_t direction) +{ + uint32_t saved_layer_state = layer_state; + + clear_keyboard(); + layer_clear(); + + while (macro_buffer != macro_end) { + process_record(macro_buffer); + macro_buffer += direction; + } + + clear_keyboard(); + + layer_state = saved_layer_state; +} + +/** + * Record a single key in a dynamic macro. + * + * @param macro_pointer[in,out] The current buffer position. + * @param macro_end2[in] The end of the other macro which shouldn't be overwritten. + * @param direction[in] Either +1 or -1, which way to iterate the buffer. + * @param record[in] The current keypress. + */ +void dynamic_macro_record_key( + keyrecord_t **macro_pointer, + keyrecord_t *macro_end2, + int8_t direction, + keyrecord_t *record) +{ + if (*macro_pointer + direction != macro_end2) { + **macro_pointer = *record; + *macro_pointer += direction; + } else { + /* Notify about the end of buffer. The blinks are paired + * because they should happen on both down and up events. */ + backlight_toggle(); + } +} + +/** + * End recording of the dynamic macro. Essentially just update the + * pointer to the end of the macro. + */ +void dynamic_macro_record_end(keyrecord_t *macro_pointer, keyrecord_t **macro_end) +{ + dynamic_macro_led_blink(); + + *macro_end = macro_pointer; +} + +/* Handle the key events related to the dynamic macros. Should be + * called from process_record_user() like this: + * + * bool process_record_user(uint16_t keycode, keyrecord_t *record) { + * if (!process_record_dynamic_macro(keycode, record)) { + * return false; + * } + * <...THE REST OF THE FUNCTION...> + * } + */ +bool process_record_dynamic_macro(uint16_t keycode, keyrecord_t *record) +{ + /* Both macros use the same buffer but read/write on different + * ends of it. + * + * Macro1 is written left-to-right starting from the beginning of + * the buffer. + * + * Macro2 is written right-to-left starting from the end of the + * buffer. + * + * ¯o_buffer macro_end + * v v + * +------------------------------------------------------------+ + * |>>>>>> MACRO1 >>>>>>| |<<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| + * +------------------------------------------------------------+ + * ^ ^ + * r_macro_end r_macro_buffer + * + * During the recording when one macro encounters the end of the + * other macro, the recording is stopped. Apart from this, there + * are no arbitrary limits for the macros' length in relation to + * each other: for example one can either have two medium sized + * macros or one long macro and one short macro. Or even one empty + * and one using the whole buffer. + */ + static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE]; + + /* Pointer to the first buffer element after the first macro. + * Initially points to the very beginning of the buffer since the + * macro is empty. */ + static keyrecord_t *macro_end = macro_buffer; + + /* The other end of the macro buffer. Serves as the beginning of + * the second macro. */ + static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1; + + /* Like macro_end but for the second macro. */ + static keyrecord_t *r_macro_end = r_macro_buffer; + + /* A persistent pointer to the current macro position (iterator) + * used during the recording. */ + static keyrecord_t *macro_pointer = NULL; + + /* 0 - no macro is being recorded right now + * 1,2 - either macro 1 or 2 is being recorded */ + static uint8_t macro_id = 0; + + if (macro_id == 0) { + /* No macro recording in progress. */ + if (!record->event.pressed) { + switch (keycode) { + case DYN_REC_START1: + dynamic_macro_record_start(¯o_pointer, macro_buffer); + macro_id = 1; + return false; + case DYN_REC_START2: + dynamic_macro_record_start(¯o_pointer, r_macro_buffer); + macro_id = 2; + return false; + case DYN_MACRO_PLAY1: + dynamic_macro_play(macro_buffer, macro_end, +1); + return false; + case DYN_MACRO_PLAY2: + dynamic_macro_play(r_macro_buffer, r_macro_end, -1); + return false; + } + } + } else { + /* A macro is being recorded right now. */ + switch (keycode) { + case MO(_DYN): + /* Use the layer key used to access the macro recording as + * a stop button. */ + if (record->event.pressed) { /* Ignore the initial release + * just after the recoding + * starts. */ + switch (macro_id) { + case 1: + dynamic_macro_record_end(macro_pointer, ¯o_end); + break; + case 2: + dynamic_macro_record_end(macro_pointer, &r_macro_end); + break; + } + macro_id = 0; + } + return false; + default: + /* Store the key in the macro buffer and process it normally. */ + switch (macro_id) { + case 1: + dynamic_macro_record_key(¯o_pointer, r_macro_end, +1, record); + break; + case 2: + dynamic_macro_record_key(¯o_pointer, macro_end, -1, record); + break; + } + return true; + break; + } + } + + return true; +} + +#endif diff --git a/quantum/keymap.h b/quantum/keymap.h index a158651839..f2d94d75c3 100644 --- a/quantum/keymap.h +++ b/quantum/keymap.h @@ -156,16 +156,16 @@ enum quantum_keycodes { BL_INC, BL_TOGG, BL_STEP, - - // RGB functionality - RGB_TOG, - RGB_MOD, - RGB_HUI, - RGB_HUD, - RGB_SAI, - RGB_SAD, - RGB_VAI, - RGB_VAD, + + // RGB functionality + RGB_TOG, + RGB_MOD, + RGB_HUI, + RGB_HUD, + RGB_SAI, + RGB_SAD, + RGB_VAI, + RGB_VAD, // Left shift, open paren KC_LSPO, @@ -309,7 +309,7 @@ enum quantum_keycodes { #define OSL(layer) (layer | QK_ONE_SHOT_LAYER) // One-shot mod -#define OSM(layer) (layer | QK_ONE_SHOT_MOD) +#define OSM(mod) (mod | QK_ONE_SHOT_MOD) // M-od, T-ap - 256 keycode max #define MT(mod, kc) (kc | QK_MOD_TAP | ((mod & 0xF) << 8)) diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c index 5429e34383..07de3ecb8f 100644 --- a/quantum/process_keycode/process_tap_dance.c +++ b/quantum/process_keycode/process_tap_dance.c @@ -1,26 +1,16 @@ #include "quantum.h" +#include "action_tapping.h" -static qk_tap_dance_state_t qk_tap_dance_state; -bool td_debug_enable = false; - -#if CONSOLE_ENABLE -#define td_debug(s) if (td_debug_enable) \ - { \ - xprintf ("D:tap_dance:%s:%s = { keycode = %d, count = %d, active = %d, pressed = %d }\n", __FUNCTION__, s, \ - qk_tap_dance_state.keycode, qk_tap_dance_state.count, \ - qk_tap_dance_state.active, qk_tap_dance_state.pressed); \ - } -#else -#define td_debug(s) -#endif +static uint16_t last_td; +static int8_t highest_td = -1; void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data) { qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; if (state->count == 1) { - register_code (pair->kc1); + register_code16 (pair->kc1); } else if (state->count == 2) { - register_code (pair->kc2); + register_code16 (pair->kc2); } } @@ -28,105 +18,117 @@ void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) { qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data; if (state->count == 1) { - unregister_code (pair->kc1); + unregister_code16 (pair->kc1); } else if (state->count == 2) { - unregister_code (pair->kc2); + unregister_code16 (pair->kc2); } } static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, - void *user_data, - qk_tap_dance_user_fn_t fn) + void *user_data, + qk_tap_dance_user_fn_t fn) { if (fn) { fn(state, user_data); } } -static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t action) +static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t *action) { - td_debug("trigger"); - _process_tap_dance_action_fn (&qk_tap_dance_state, action.user_data, action.fn.on_each_tap); + _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_each_tap); } -static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t action) +static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t *action) { - td_debug("trigger"); - _process_tap_dance_action_fn (&qk_tap_dance_state, action.user_data, action.fn.on_dance_finished); + if (action->state.finished) + return; + action->state.finished = true; + _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished); } -static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t action) +static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action) { - td_debug("trigger") - _process_tap_dance_action_fn (&qk_tap_dance_state, action.user_data, action.fn.on_reset); + _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset); } bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { - bool r = true; uint16_t idx = keycode - QK_TAP_DANCE; - qk_tap_dance_action_t action; + qk_tap_dance_action_t *action; + + if (last_td && last_td != keycode) { + (&tap_dance_actions[last_td - QK_TAP_DANCE])->state.interrupted = true; + } switch(keycode) { case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: - action = tap_dance_actions[idx]; - - process_tap_dance_action_on_each_tap (action); - if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) { - process_tap_dance_action_on_dance_finished (action); - } else if (qk_tap_dance_state.active && qk_tap_dance_state.pressed) { - reset_tap_dance (&qk_tap_dance_state); - } else { - r = false; - } + if ((int16_t)idx > highest_td) + highest_td = idx; + action = &tap_dance_actions[idx]; - qk_tap_dance_state.active = true; - qk_tap_dance_state.pressed = record->event.pressed; + action->state.keycode = keycode; + action->state.pressed = record->event.pressed; if (record->event.pressed) { - qk_tap_dance_state.keycode = keycode; - qk_tap_dance_state.timer = timer_read (); - qk_tap_dance_state.count++; + action->state.count++; + action->state.timer = timer_read(); + + if (last_td && last_td != keycode) { + qk_tap_dance_action_t *paction = &tap_dance_actions[last_td - QK_TAP_DANCE]; + paction->state.interrupted = true; + process_tap_dance_action_on_dance_finished (paction); + reset_tap_dance (&paction->state); + } } + last_td = keycode; + break; default: - if (qk_tap_dance_state.keycode) { - // if we are here, the tap dance was interrupted by a different key - idx = qk_tap_dance_state.keycode - QK_TAP_DANCE; - action = tap_dance_actions[idx]; + if (!record->event.pressed) + return true; + + if (highest_td == -1) + return true; - process_tap_dance_action_on_each_tap (action); + for (int i = 0; i <= highest_td; i++) { + action = &tap_dance_actions[i]; + if (action->state.count == 0) + continue; + action->state.interrupted = true; process_tap_dance_action_on_dance_finished (action); - reset_tap_dance (&qk_tap_dance_state); - qk_tap_dance_state.active = false; + reset_tap_dance (&action->state); } break; } - return r; + return true; } void matrix_scan_tap_dance () { - if (qk_tap_dance_state.active && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) { - // if we are here, the tap dance was timed out - uint16_t idx = qk_tap_dance_state.keycode - QK_TAP_DANCE; - qk_tap_dance_action_t action = tap_dance_actions[idx]; + if (highest_td == -1) + return; + + for (int i = 0; i <= highest_td; i++) { + qk_tap_dance_action_t *action = &tap_dance_actions[i]; - process_tap_dance_action_on_dance_finished (action); - reset_tap_dance (&qk_tap_dance_state); + if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) { + process_tap_dance_action_on_dance_finished (action); + reset_tap_dance (&action->state); + } } } void reset_tap_dance (qk_tap_dance_state_t *state) { - uint16_t idx = state->keycode - QK_TAP_DANCE; - qk_tap_dance_action_t action; + qk_tap_dance_action_t *action; if (state->pressed) return; - action = tap_dance_actions[idx]; + action = &tap_dance_actions[state->keycode - QK_TAP_DANCE]; + process_tap_dance_action_on_reset (action); - state->keycode = 0; state->count = 0; - state->active = false; + state->interrupted = false; + state->finished = false; + last_td = 0; } diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h index 6a1258067e..d7b857bdc6 100644 --- a/quantum/process_keycode/process_tap_dance.h +++ b/quantum/process_keycode/process_tap_dance.h @@ -11,8 +11,9 @@ typedef struct uint8_t count; uint16_t keycode; uint16_t timer; - bool active:1; - bool pressed:1; + bool interrupted; + bool pressed; + bool finished; } qk_tap_dance_state_t; #define TD(n) (QK_TAP_DANCE + n) @@ -26,6 +27,7 @@ typedef struct qk_tap_dance_user_fn_t on_dance_finished; qk_tap_dance_user_fn_t on_reset; } fn; + qk_tap_dance_state_t state; void *user_data; } qk_tap_dance_action_t; @@ -48,8 +50,7 @@ typedef struct .fn = { user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_reset } \ } -extern const qk_tap_dance_action_t tap_dance_actions[]; -extern bool td_debug_enable; +extern qk_tap_dance_action_t tap_dance_actions[]; /* To be used internally */ diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c index ad5d7f86b7..a5d7dca21e 100644 --- a/quantum/process_keycode/process_unicode.c +++ b/quantum/process_keycode/process_unicode.c @@ -13,45 +13,200 @@ uint16_t hex_to_keycode(uint8_t hex) } } -void set_unicode_mode(uint8_t os_target) +void set_unicode_input_mode(uint8_t os_target) { input_mode = os_target; } +uint8_t get_unicode_input_mode(void) { + return input_mode; +} + +__attribute__((weak)) +void unicode_input_start (void) { + switch(input_mode) { + case UC_OSX: + register_code(KC_LALT); + break; + case UC_LNX: + register_code(KC_LCTL); + register_code(KC_LSFT); + register_code(KC_U); + unregister_code(KC_U); + unregister_code(KC_LSFT); + unregister_code(KC_LCTL); + break; + case UC_WIN: + register_code(KC_LALT); + register_code(KC_PPLS); + unregister_code(KC_PPLS); + break; + } + wait_ms(UNICODE_TYPE_DELAY); +} + +__attribute__((weak)) +void unicode_input_finish (void) { + switch(input_mode) { + case UC_OSX: + case UC_WIN: + unregister_code(KC_LALT); + break; + case UC_LNX: + register_code(KC_SPC); + unregister_code(KC_SPC); + break; + } +} + +void register_hex(uint16_t hex) { + for(int i = 3; i >= 0; i--) { + uint8_t digit = ((hex >> (i*4)) & 0xF); + register_code(hex_to_keycode(digit)); + unregister_code(hex_to_keycode(digit)); + } +} + bool process_unicode(uint16_t keycode, keyrecord_t *record) { if (keycode > QK_UNICODE && record->event.pressed) { uint16_t unicode = keycode & 0x7FFF; - switch(input_mode) { - case UC_OSX: - register_code(KC_LALT); - break; - case UC_LNX: - register_code(KC_LCTL); - register_code(KC_LSFT); - register_code(KC_U); - unregister_code(KC_U); - break; - case UC_WIN: - register_code(KC_LALT); - register_code(KC_PPLS); - unregister_code(KC_PPLS); - break; + unicode_input_start(); + register_hex(unicode); + unicode_input_finish(); + } + return true; +} + +#ifdef UCIS_ENABLE +qk_ucis_state_t qk_ucis_state; + +void qk_ucis_start(void) { + qk_ucis_state.count = 0; + qk_ucis_state.in_progress = true; + + qk_ucis_start_user(); +} + +__attribute__((weak)) +void qk_ucis_start_user(void) { + unicode_input_start(); + register_hex(0x2328); + unicode_input_finish(); +} + +static bool is_uni_seq(char *seq) { + uint8_t i; + + for (i = 0; seq[i]; i++) { + uint16_t code; + if (('1' <= seq[i]) && (seq[i] <= '0')) + code = seq[i] - '1' + KC_1; + else + code = seq[i] - 'a' + KC_A; + + if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code) + return false; + } + + return (qk_ucis_state.codes[i] == KC_ENT || + qk_ucis_state.codes[i] == KC_SPC); +} + +__attribute__((weak)) +void qk_ucis_symbol_fallback (void) { + for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { + uint8_t code = qk_ucis_state.codes[i]; + register_code(code); + unregister_code(code); + wait_ms(UNICODE_TYPE_DELAY); + } +} + +void register_ucis(const char *hex) { + for(int i = 0; hex[i]; i++) { + uint8_t kc = 0; + char c = hex[i]; + + switch (c) { + case '0': + kc = KC_0; + break; + case '1' ... '9': + kc = c - '1' + KC_1; + break; + case 'a' ... 'f': + kc = c - 'a' + KC_A; + break; + case 'A' ... 'F': + kc = c - 'A' + KC_A; + break; } - for(int i = 3; i >= 0; i--) { - uint8_t digit = ((unicode >> (i*4)) & 0xF); - register_code(hex_to_keycode(digit)); - unregister_code(hex_to_keycode(digit)); + + if (kc) { + register_code (kc); + unregister_code (kc); + wait_ms (UNICODE_TYPE_DELAY); } - switch(input_mode) { - case UC_OSX: - case UC_WIN: - unregister_code(KC_LALT); - break; - case UC_LNX: - unregister_code(KC_LCTL); - unregister_code(KC_LSFT); + } +} + +bool process_ucis (uint16_t keycode, keyrecord_t *record) { + uint8_t i; + + if (!qk_ucis_state.in_progress) + return true; + + if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH && + !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) { + return false; + } + + if (!record->event.pressed) + return true; + + qk_ucis_state.codes[qk_ucis_state.count] = keycode; + qk_ucis_state.count++; + + if (keycode == KC_BSPC) { + if (qk_ucis_state.count >= 2) { + qk_ucis_state.count -= 2; + return true; + } else { + qk_ucis_state.count--; + return false; + } + } + + if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) { + bool symbol_found = false; + + for (i = qk_ucis_state.count; i > 0; i--) { + register_code (KC_BSPC); + unregister_code (KC_BSPC); + wait_ms(UNICODE_TYPE_DELAY); + } + + if (keycode == KC_ESC) { + qk_ucis_state.in_progress = false; + return false; + } + + unicode_input_start(); + for (i = 0; ucis_symbol_table[i].symbol; i++) { + if (is_uni_seq (ucis_symbol_table[i].symbol)) { + symbol_found = true; + register_ucis(ucis_symbol_table[i].code + 2); break; + } } + if (!symbol_found) { + qk_ucis_symbol_fallback(); + } + unicode_input_finish(); + + qk_ucis_state.in_progress = false; + return false; } return true; -}
\ No newline at end of file +} +#endif diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h index ca17f8f669..27f8072ee6 100644 --- a/quantum/process_keycode/process_unicode.h +++ b/quantum/process_keycode/process_unicode.h @@ -8,10 +8,49 @@ #define UC_WIN 2 #define UC_BSD 3 +#ifndef UNICODE_TYPE_DELAY +#define UNICODE_TYPE_DELAY 10 +#endif + void set_unicode_input_mode(uint8_t os_target); +uint8_t get_unicode_input_mode(void); +void unicode_input_start(void); +void unicode_input_finish(void); +void register_hex(uint16_t hex); bool process_unicode(uint16_t keycode, keyrecord_t *record); +#ifdef UCIS_ENABLE +#ifndef UCIS_MAX_SYMBOL_LENGTH +#define UCIS_MAX_SYMBOL_LENGTH 32 +#endif + +typedef struct { + char *symbol; + char *code; +} qk_ucis_symbol_t; + +typedef struct { + uint8_t count; + uint16_t codes[UCIS_MAX_SYMBOL_LENGTH]; + bool in_progress:1; +} qk_ucis_state_t; + +extern qk_ucis_state_t qk_ucis_state; + +#define UCIS_TABLE(...) {__VA_ARGS__, {NULL, NULL}} +#define UCIS_SYM(name, code) {name, #code} + +extern const qk_ucis_symbol_t ucis_symbol_table[]; + +void qk_ucis_start(void); +void qk_ucis_start_user(void); +void qk_ucis_symbol_fallback (void); +void register_ucis(const char *hex); +bool process_ucis (uint16_t keycode, keyrecord_t *record); + +#endif + #define UC_BSPC UC(0x0008) #define UC_SPC UC(0x0020) @@ -119,4 +158,4 @@ bool process_unicode(uint16_t keycode, keyrecord_t *record); #define UC_TILD UC(0x007E) #define UC_DEL UC(0x007F) -#endif
\ No newline at end of file +#endif diff --git a/quantum/quantum.c b/quantum/quantum.c index bc2da510f2..e3a20f43e0 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -1,5 +1,42 @@ #include "quantum.h" +static void do_code16 (uint16_t code, void (*f) (uint8_t)) { + switch (code) { + case QK_MODS ... QK_MODS_MAX: + break; + default: + return; + } + + if (code & QK_LCTL) + f(KC_LCTL); + if (code & QK_LSFT) + f(KC_LSFT); + if (code & QK_LALT) + f(KC_LALT); + if (code & QK_LGUI) + f(KC_LGUI); + + if (code & QK_RCTL) + f(KC_RCTL); + if (code & QK_RSFT) + f(KC_RSFT); + if (code & QK_RALT) + f(KC_RALT); + if (code & QK_RGUI) + f(KC_RGUI); +} + +void register_code16 (uint16_t code) { + do_code16 (code, register_code); + register_code (code); +} + +void unregister_code16 (uint16_t code) { + unregister_code (code); + do_code16 (code, unregister_code); +} + __attribute__ ((weak)) bool process_action_kb(keyrecord_t *record) { return true; @@ -46,18 +83,20 @@ bool process_record_quantum(keyrecord_t *record) { uint16_t keycode; #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) - uint8_t layer; + /* TODO: Use store_or_get_action() or a similar function. */ + if (!disable_action_cache) { + uint8_t layer; - if (record->event.pressed) { - layer = layer_switch_get_layer(key); - update_source_layers_cache(key, layer); - } else { - layer = read_source_layers_cache(key); - } - keycode = keymap_key_to_keycode(layer, key); - #else - keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key); + if (record->event.pressed) { + layer = layer_switch_get_layer(key); + update_source_layers_cache(key, layer); + } else { + layer = read_source_layers_cache(key); + } + keycode = keymap_key_to_keycode(layer, key); + } else #endif + keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key); // This is how you use actions here // if (keycode == KC_LEAD) { @@ -87,6 +126,9 @@ bool process_record_quantum(keyrecord_t *record) { #ifdef UNICODE_ENABLE process_unicode(keycode, record) && #endif + #ifdef UCIS_ENABLE + process_ucis(keycode, record) && + #endif true)) { return false; } diff --git a/quantum/quantum.h b/quantum/quantum.h index 6e3fbcc792..0c60466495 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -83,6 +83,9 @@ void reset_keyboard(void); void startup_user(void); void shutdown_user(void); +void register_code16 (uint16_t code); +void unregister_code16 (uint16_t code); + #ifdef BACKLIGHT_ENABLE void backlight_init_ports(void); diff --git a/quantum/serial_link/protocol/byte_stuffer.c b/quantum/serial_link/protocol/byte_stuffer.c index fb4c45a8dc..2c87d64c29 100644 --- a/quantum/serial_link/protocol/byte_stuffer.c +++ b/quantum/serial_link/protocol/byte_stuffer.c @@ -31,9 +31,6 @@ SOFTWARE. // https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing // http://www.stuartcheshire.org/papers/COBSforToN.pdf -#define MAX_FRAME_SIZE 1024 -#define NUM_LINKS 2 - typedef struct byte_stuffer_state { uint16_t next_zero; uint16_t data_pos; diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h index 2cc88beb42..97e8968564 100644 --- a/quantum/serial_link/protocol/byte_stuffer.h +++ b/quantum/serial_link/protocol/byte_stuffer.h @@ -27,6 +27,9 @@ SOFTWARE. #include <stdint.h> +#define MAX_FRAME_SIZE 1024 +#define NUM_LINKS 2 + void init_byte_stuffer(void); void byte_stuffer_recv_byte(uint8_t link, uint8_t data); void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size); diff --git a/quantum/serial_link/protocol/transport.c b/quantum/serial_link/protocol/transport.c index f418d11ceb..ff795fe201 100644 --- a/quantum/serial_link/protocol/transport.c +++ b/quantum/serial_link/protocol/transport.c @@ -31,6 +31,10 @@ SOFTWARE. static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS]; static uint32_t num_remote_objects = 0; +void reinitialize_serial_link_transport(void) { + num_remote_objects = 0; +} + void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) { unsigned int i; for(i=0;i<_num_remote_objects;i++) { diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h index 9a052d8809..2c5d890b21 100644 --- a/quantum/serial_link/protocol/transport.h +++ b/quantum/serial_link/protocol/transport.h @@ -82,7 +82,7 @@ typedef struct { \ remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ - return triple_buffer_read_internal(obj->object_size, tb); \ + return (type*)triple_buffer_read_internal(obj->object_size, tb); \ } #define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \ @@ -112,7 +112,7 @@ typedef struct { \ remote_object_t* obj = (remote_object_t*)&remote_object_##name; \ uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\ triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ - return triple_buffer_read_internal(obj->object_size, tb); \ + return (type*)triple_buffer_read_internal(obj->object_size, tb); \ } #define SLAVE_TO_MASTER_OBJECT(name, type) \ @@ -139,12 +139,13 @@ typedef struct { \ uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\ start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \ triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \ - return triple_buffer_read_internal(obj->object_size, tb); \ + return (type*)triple_buffer_read_internal(obj->object_size, tb); \ } #define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects); +void reinitialize_serial_link_transport(void); void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size); void update_transport(void); diff --git a/quantum/serial_link/tests/byte_stuffer_tests.c b/quantum/serial_link/tests/byte_stuffer_tests.cpp index 64b170e8c1..ff49d727bb 100644 --- a/quantum/serial_link/tests/byte_stuffer_tests.c +++ b/quantum/serial_link/tests/byte_stuffer_tests.cpp @@ -22,70 +22,90 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <cgreen/cgreen.h> -#include <cgreen/mocks.h> +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include <vector> +#include <algorithm> +extern "C" { #include "serial_link/protocol/byte_stuffer.h" -#include "serial_link/protocol/byte_stuffer.c" #include "serial_link/protocol/frame_validator.h" #include "serial_link/protocol/physical.h" +} -static uint8_t sent_data[MAX_FRAME_SIZE*2]; -static uint16_t sent_data_size; +using testing::_; +using testing::ElementsAreArray; +using testing::Args; -Describe(ByteStuffer); -BeforeEach(ByteStuffer) { - init_byte_stuffer(); - sent_data_size = 0; -} -AfterEach(ByteStuffer) {} +class ByteStuffer : public ::testing::Test{ +public: + ByteStuffer() { + Instance = this; + init_byte_stuffer(); + } -void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { - mock(data, size); -} + ~ByteStuffer() { + Instance = nullptr; + } + + MOCK_METHOD3(validator_recv_frame, void (uint8_t link, uint8_t* data, uint16_t size)); + + void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + std::copy(data, data + size, std::back_inserter(sent_data)); + } + std::vector<uint8_t> sent_data; -void send_data(uint8_t link, const uint8_t* data, uint16_t size) { - memcpy(sent_data + sent_data_size, data, size); - sent_data_size += size; + static ByteStuffer* Instance; +}; + +ByteStuffer* ByteStuffer::Instance = nullptr; + +extern "C" { + void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { + ByteStuffer::Instance->validator_recv_frame(link, data, size); + } + + void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + ByteStuffer::Instance->send_data(link, data, size); + } } -Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { - never_expect(validator_recv_frame); +TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) { + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .Times(0); byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { - never_expect(validator_recv_frame); +TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) { + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .Times(0); byte_stuffer_recv_byte(0, 0xFF); } -Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) { - never_expect(validator_recv_frame); +TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) { + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .Times(0); byte_stuffer_recv_byte(0, 0x4A); } -Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) { - never_expect(validator_recv_frame); +TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) { + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .Times(0); byte_stuffer_recv_byte(0, 1); byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_single_byte_valid_frame) { +TEST_F(ByteStuffer, receives_single_byte_valid_frame) { uint8_t expected[] = {0x37}; - expect(validator_recv_frame, - when(size, is_equal_to(1)), - when(data, is_equal_to_contents_of(expected, 1)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 2); byte_stuffer_recv_byte(0, 0x37); byte_stuffer_recv_byte(0, 0); } - -Ensure(ByteStuffer, receives_three_bytes_valid_frame) { +TEST_F(ByteStuffer, receives_three_bytes_valid_frame) { uint8_t expected[] = {0x37, 0x99, 0xFF}; - expect(validator_recv_frame, - when(size, is_equal_to(3)), - when(data, is_equal_to_contents_of(expected, 3)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 4); byte_stuffer_recv_byte(0, 0x37); byte_stuffer_recv_byte(0, 0x99); @@ -93,23 +113,19 @@ Ensure(ByteStuffer, receives_three_bytes_valid_frame) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_single_zero_valid_frame) { +TEST_F(ByteStuffer, receives_single_zero_valid_frame) { uint8_t expected[] = {0}; - expect(validator_recv_frame, - when(size, is_equal_to(1)), - when(data, is_equal_to_contents_of(expected, 1)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 1); byte_stuffer_recv_byte(0, 1); byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_valid_frame_with_zeroes) { +TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) { uint8_t expected[] = {5, 0, 3, 0}; - expect(validator_recv_frame, - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(expected, 4)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 2); byte_stuffer_recv_byte(0, 5); byte_stuffer_recv_byte(0, 2); @@ -118,17 +134,14 @@ Ensure(ByteStuffer, receives_valid_frame_with_zeroes) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_two_valid_frames) { + +TEST_F(ByteStuffer, receives_two_valid_frames) { uint8_t expected1[] = {5, 0}; uint8_t expected2[] = {3}; - expect(validator_recv_frame, - when(size, is_equal_to(2)), - when(data, is_equal_to_contents_of(expected1, 2)) - ); - expect(validator_recv_frame, - when(size, is_equal_to(1)), - when(data, is_equal_to_contents_of(expected2, 1)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected1))); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected2))); byte_stuffer_recv_byte(1, 2); byte_stuffer_recv_byte(1, 5); byte_stuffer_recv_byte(1, 1); @@ -138,12 +151,10 @@ Ensure(ByteStuffer, receives_two_valid_frames) { byte_stuffer_recv_byte(1, 0); } -Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) { +TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) { uint8_t expected[] = {5, 7}; - expect(validator_recv_frame, - when(size, is_equal_to(2)), - when(data, is_equal_to_contents_of(expected, 2)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(1, 3); byte_stuffer_recv_byte(1, 1); byte_stuffer_recv_byte(1, 0); @@ -153,12 +164,10 @@ Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) { byte_stuffer_recv_byte(1, 0); } -Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { +TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { uint8_t expected[] = {5, 7}; - expect(validator_recv_frame, - when(size, is_equal_to(2)), - when(data, is_equal_to_contents_of(expected, 2)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 2); byte_stuffer_recv_byte(0, 9); byte_stuffer_recv_byte(0, 4); // This should have been zero @@ -169,16 +178,14 @@ Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) { +TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) { uint8_t expected[254]; int i; for (i=0;i<254;i++) { expected[i] = i + 1; } - expect(validator_recv_frame, - when(size, is_equal_to(254)), - when(data, is_equal_to_contents_of(expected, 254)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 0xFF); for (i=0;i<254;i++) { byte_stuffer_recv_byte(0, i+1); @@ -186,17 +193,15 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_ byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) { +TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) { uint8_t expected[255]; int i; for (i=0;i<254;i++) { expected[i] = i + 1; } expected[254] = 7; - expect(validator_recv_frame, - when(size, is_equal_to(255)), - when(data, is_equal_to_contents_of(expected, 255)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 0xFF); for (i=0;i<254;i++) { byte_stuffer_recv_byte(0, i+1); @@ -206,17 +211,15 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_ byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) { +TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) { uint8_t expected[255]; int i; for (i=0;i<254;i++) { expected[i] = i + 1; } expected[254] = 0; - expect(validator_recv_frame, - when(size, is_equal_to(255)), - when(data, is_equal_to_contents_of(expected, 255)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 0xFF); for (i=0;i<254;i++) { byte_stuffer_recv_byte(0, i+1); @@ -226,7 +229,7 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_ byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_two_long_frames_and_some_more) { +TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) { uint8_t expected[515]; int i; int j; @@ -238,10 +241,8 @@ Ensure(ByteStuffer, receives_two_long_frames_and_some_more) { for (i=0;i<7;i++) { expected[254*2+i] = i + 1; } - expect(validator_recv_frame, - when(size, is_equal_to(515)), - when(data, is_equal_to_contents_of(expected, 510)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); byte_stuffer_recv_byte(0, 0xFF); for (i=0;i<254;i++) { byte_stuffer_recv_byte(0, i+1); @@ -261,12 +262,10 @@ Ensure(ByteStuffer, receives_two_long_frames_and_some_more) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { +TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { uint8_t expected[MAX_FRAME_SIZE] = {}; - expect(validator_recv_frame, - when(size, is_equal_to(MAX_FRAME_SIZE)), - when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); int i; byte_stuffer_recv_byte(0, 1); for(i=0;i<MAX_FRAME_SIZE;i++) { @@ -275,9 +274,10 @@ Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { +TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { uint8_t expected[1] = {0}; - never_expect(validator_recv_frame); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .Times(0); int i; byte_stuffer_recv_byte(0, 1); for(i=0;i<MAX_FRAME_SIZE;i++) { @@ -287,12 +287,10 @@ Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) { +TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) { uint8_t expected[1] = {1}; - expect(validator_recv_frame, - when(size, is_equal_to(1)), - when(data, is_equal_to_contents_of(expected, 1)) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); int i; byte_stuffer_recv_byte(0, 1); for(i=0;i<MAX_FRAME_SIZE;i++) { @@ -303,76 +301,68 @@ Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) { byte_stuffer_recv_byte(0, 0); } -Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) { - assert_that(sent_data_size, is_equal_to(0)); +TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) { + EXPECT_EQ(sent_data.size(), 0); byte_stuffer_send_frame(0, NULL, 0); } -Ensure(ByteStuffer, send_one_byte_frame) { +TEST_F(ByteStuffer, send_one_byte_frame) { uint8_t data[] = {5}; byte_stuffer_send_frame(1, data, 1); uint8_t expected[] = {2, 5, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_two_byte_frame) { +TEST_F(ByteStuffer, sends_two_byte_frame) { uint8_t data[] = {5, 0x77}; byte_stuffer_send_frame(0, data, 2); uint8_t expected[] = {3, 5, 0x77, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_one_byte_frame_with_zero) { +TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) { uint8_t data[] = {0}; byte_stuffer_send_frame(0, data, 1); uint8_t expected[] = {1, 1, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) { +TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) { uint8_t data[] = {0, 9}; byte_stuffer_send_frame(1, data, 2); uint8_t expected[] = {1, 2, 9, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) { +TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) { uint8_t data[] = {9, 0}; byte_stuffer_send_frame(1, data, 2); uint8_t expected[] = {2, 9, 1, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) { +TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) { uint8_t data[] = {9, 0, 0x68}; byte_stuffer_send_frame(0, data, 3); uint8_t expected[] = {2, 9, 2, 0x68, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) { +TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) { uint8_t data[] = {0, 0x55, 0}; byte_stuffer_send_frame(0, data, 3); uint8_t expected[] = {1, 2, 0x55, 1, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) { +TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) { uint8_t data[] = {0, 0, 0}; byte_stuffer_send_frame(0, data, 3); uint8_t expected[] = {1, 1, 1, 1, 0}; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) { +TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) { uint8_t data[254]; int i; for(i=0;i<254;i++) { @@ -385,11 +375,10 @@ Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) { expected[i] = i; } expected[255] = 0; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) { +TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) { uint8_t data[255]; int i; for(i=0;i<255;i++) { @@ -404,17 +393,16 @@ Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) { expected[255] = 2; expected[256] = 255; expected[257] = 0; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { +TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { uint8_t data[255]; int i; for(i=0;i<254;i++) { data[i] = i + 1; } - data[255] = 0; + data[254] = 0; byte_stuffer_send_frame(0, data, 255); uint8_t expected[258]; expected[0] = 0xFF; @@ -424,53 +412,46 @@ Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) { expected[255] = 1; expected[256] = 1; expected[257] = 0; - assert_that(sent_data_size, is_equal_to(sizeof(expected))); - assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected))); + EXPECT_THAT(sent_data, ElementsAreArray(expected)); } -Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) { +TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) { uint8_t original_data[] = { 1, 2, 3}; byte_stuffer_send_frame(0, original_data, sizeof(original_data)); - expect(validator_recv_frame, - when(size, is_equal_to(sizeof(original_data))), - when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(original_data))); int i; - for(i=0;i<sent_data_size;i++) { - byte_stuffer_recv_byte(1, sent_data[i]); + for(auto& d : sent_data) { + byte_stuffer_recv_byte(1, d); } } -Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) { +TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) { uint8_t original_data[] = { 1, 0, 3, 0, 0, 9}; byte_stuffer_send_frame(1, original_data, sizeof(original_data)); - expect(validator_recv_frame, - when(size, is_equal_to(sizeof(original_data))), - when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) - ); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(original_data))); int i; - for(i=0;i<sent_data_size;i++) { - byte_stuffer_recv_byte(0, sent_data[i]); + for(auto& d : sent_data) { + byte_stuffer_recv_byte(1, d); } } -Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) { +TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) { uint8_t original_data[254]; int i; for(i=0;i<254;i++) { original_data[i] = i + 1; } byte_stuffer_send_frame(0, original_data, sizeof(original_data)); - expect(validator_recv_frame, - when(size, is_equal_to(sizeof(original_data))), - when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) - ); - for(i=0;i<sent_data_size;i++) { - byte_stuffer_recv_byte(1, sent_data[i]); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(original_data))); + for(auto& d : sent_data) { + byte_stuffer_recv_byte(1, d); } } -Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { +TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { uint8_t original_data[256]; int i; for(i=0;i<254;i++) { @@ -479,16 +460,14 @@ Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) { original_data[254] = 22; original_data[255] = 23; byte_stuffer_send_frame(0, original_data, sizeof(original_data)); - expect(validator_recv_frame, - when(size, is_equal_to(sizeof(original_data))), - when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) - ); - for(i=0;i<sent_data_size;i++) { - byte_stuffer_recv_byte(1, sent_data[i]); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(original_data))); + for(auto& d : sent_data) { + byte_stuffer_recv_byte(1, d); } } -Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { +TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { uint8_t original_data[255]; int i; for(i=0;i<254;i++) { @@ -496,11 +475,9 @@ Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) { } original_data[254] = 0; byte_stuffer_send_frame(0, original_data, sizeof(original_data)); - expect(validator_recv_frame, - when(size, is_equal_to(sizeof(original_data))), - when(data, is_equal_to_contents_of(original_data, sizeof(original_data))) - ); - for(i=0;i<sent_data_size;i++) { - byte_stuffer_recv_byte(1, sent_data[i]); + EXPECT_CALL(*this, validator_recv_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(original_data))); + for(auto& d : sent_data) { + byte_stuffer_recv_byte(1, d); } } diff --git a/quantum/serial_link/tests/frame_router_tests.c b/quantum/serial_link/tests/frame_router_tests.c deleted file mode 100644 index 6c806fa939..0000000000 --- a/quantum/serial_link/tests/frame_router_tests.c +++ /dev/null @@ -1,231 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2016 Fred Sundvik - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include <cgreen/cgreen.h> -#include <cgreen/mocks.h> -#include "serial_link/protocol/byte_stuffer.c" -#include "serial_link/protocol/frame_validator.c" -#include "serial_link/protocol/frame_router.c" -#include "serial_link/protocol/transport.h" - -static uint8_t received_data[256]; -static uint16_t received_data_size; - -typedef struct { - uint8_t sent_data[256]; - uint16_t sent_data_size; -} receive_buffer_t; - -typedef struct { - receive_buffer_t send_buffers[2]; -} router_buffer_t; - -router_buffer_t router_buffers[8]; - -router_buffer_t* current_router_buffer; - - -Describe(FrameRouter); -BeforeEach(FrameRouter) { - init_byte_stuffer(); - memset(router_buffers, 0, sizeof(router_buffers)); - current_router_buffer = 0; -} -AfterEach(FrameRouter) {} - -typedef struct { - uint32_t data; - uint8_t extra[16]; -} frame_buffer_t; - - -void send_data(uint8_t link, const uint8_t* data, uint16_t size) { - receive_buffer_t* buffer = ¤t_router_buffer->send_buffers[link]; - memcpy(buffer->sent_data + buffer->sent_data_size, data, size); - buffer->sent_data_size += size; -} - -static void receive_data(uint8_t link, uint8_t* data, uint16_t size) { - int i; - for(i=0;i<size;i++) { - byte_stuffer_recv_byte(link, data[i]); - } -} - -static void activate_router(uint8_t num) { - current_router_buffer = router_buffers + num; - router_set_master(num==0); -} - -static void simulate_transport(uint8_t from, uint8_t to) { - activate_router(to); - if (from > to) { - receive_data(DOWN_LINK, - router_buffers[from].send_buffers[UP_LINK].sent_data, - router_buffers[from].send_buffers[UP_LINK].sent_data_size); - } - else if(to > from) { - receive_data(UP_LINK, - router_buffers[from].send_buffers[DOWN_LINK].sent_data, - router_buffers[from].send_buffers[DOWN_LINK].sent_data_size); - } -} - -void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { - mock(from, data, size); -} - - -Ensure(FrameRouter, master_broadcast_is_received_by_everyone) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(0); - router_send_frame(0xFF, (uint8_t*)&data, 4); - assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - - expect(transport_recv_frame, - when(from, is_equal_to(0)), - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(&data.data, 4)) - ); - simulate_transport(0, 1); - assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - - expect(transport_recv_frame, - when(from, is_equal_to(0)), - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(&data.data, 4)) - ); - simulate_transport(1, 2); - assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); -} - -Ensure(FrameRouter, master_send_is_received_by_targets) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(0); - router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4); - assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - - simulate_transport(0, 1); - assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - - expect(transport_recv_frame, - when(from, is_equal_to(0)), - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(&data.data, 4)) - ); - simulate_transport(1, 2); - assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - - expect(transport_recv_frame, - when(from, is_equal_to(0)), - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(&data.data, 4)) - ); - simulate_transport(2, 3); - assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); -} - -Ensure(FrameRouter, first_link_sends_to_master) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(1); - router_send_frame(0, (uint8_t*)&data, 4); - assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); - - expect(transport_recv_frame, - when(from, is_equal_to(1)), - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(&data.data, 4)) - ); - simulate_transport(1, 0); - assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); - assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); -} - -Ensure(FrameRouter, second_link_sends_to_master) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(2); - router_send_frame(0, (uint8_t*)&data, 4); - assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); - - simulate_transport(2, 1); - assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); - - expect(transport_recv_frame, - when(from, is_equal_to(2)), - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(&data.data, 4)) - ); - simulate_transport(1, 0); - assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); - assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); -} - -Ensure(FrameRouter, master_sends_to_master_does_nothing) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(0); - router_send_frame(0, (uint8_t*)&data, 4); - assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); -} - -Ensure(FrameRouter, link_sends_to_other_link_does_nothing) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(1); - router_send_frame(2, (uint8_t*)&data, 4); - assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); -} - -Ensure(FrameRouter, master_receives_on_uplink_does_nothing) { - frame_buffer_t data; - data.data = 0xAB7055BB; - activate_router(1); - router_send_frame(0, (uint8_t*)&data, 4); - assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0)); - assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); - - never_expect(transport_recv_frame); - activate_router(0); - receive_data(UP_LINK, - router_buffers[1].send_buffers[UP_LINK].sent_data, - router_buffers[1].send_buffers[UP_LINK].sent_data_size); - assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0)); - assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0)); -} diff --git a/quantum/serial_link/tests/frame_router_tests.cpp b/quantum/serial_link/tests/frame_router_tests.cpp new file mode 100644 index 0000000000..2bd5bf830d --- /dev/null +++ b/quantum/serial_link/tests/frame_router_tests.cpp @@ -0,0 +1,229 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include <array> +extern "C" { + #include "serial_link/protocol/transport.h" + #include "serial_link/protocol/byte_stuffer.h" + #include "serial_link/protocol/frame_router.h" +} + +using testing::_; +using testing::ElementsAreArray; +using testing::Args; + +class FrameRouter : public testing::Test { +public: + FrameRouter() : + current_router_buffer(nullptr) + { + Instance = this; + init_byte_stuffer(); + } + + ~FrameRouter() { + Instance = nullptr; + } + + void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + auto& buffer = current_router_buffer->send_buffers[link]; + std::copy(data, data + size, std::back_inserter(buffer)); + } + + void receive_data(uint8_t link, uint8_t* data, uint16_t size) { + int i; + for(i=0;i<size;i++) { + byte_stuffer_recv_byte(link, data[i]); + } + } + + void activate_router(uint8_t num) { + current_router_buffer = router_buffers + num; + router_set_master(num==0); + } + + void simulate_transport(uint8_t from, uint8_t to) { + activate_router(to); + if (from > to) { + receive_data(DOWN_LINK, + router_buffers[from].send_buffers[UP_LINK].data(), + router_buffers[from].send_buffers[UP_LINK].size()); + } + else if(to > from) { + receive_data(UP_LINK, + router_buffers[from].send_buffers[DOWN_LINK].data(), + router_buffers[from].send_buffers[DOWN_LINK].size()); + } + } + + MOCK_METHOD3(transport_recv_frame, void (uint8_t from, uint8_t* data, uint16_t size)); + + std::vector<uint8_t> received_data; + + struct router_buffer { + std::vector<uint8_t> send_buffers[2]; + }; + + router_buffer router_buffers[8]; + router_buffer* current_router_buffer; + + static FrameRouter* Instance; +}; + +FrameRouter* FrameRouter::Instance = nullptr; + + +typedef struct { + std::array<uint8_t, 4> data; + uint8_t extra[16]; +} frame_buffer_t; + + +extern "C" { + void send_data(uint8_t link, const uint8_t* data, uint16_t size) { + FrameRouter::Instance->send_data(link, data, size); + } + + + void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { + FrameRouter::Instance->transport_recv_frame(from, data, size); + } +} + +TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(0); + router_send_frame(0xFF, (uint8_t*)&data, 4); + EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); + EXPECT_CALL(*this, transport_recv_frame(0, _, _)) + .With(Args<1, 2>(ElementsAreArray(data.data))); + simulate_transport(0, 1); + EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); + + EXPECT_CALL(*this, transport_recv_frame(0, _, _)) + .With(Args<1, 2>(ElementsAreArray(data.data))); + simulate_transport(1, 2); + EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0); +} + +TEST_F(FrameRouter, master_send_is_received_by_targets) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(0); + router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4); + EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); + + simulate_transport(0, 1); + EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); + + EXPECT_CALL(*this, transport_recv_frame(0, _, _)) + .With(Args<1, 2>(ElementsAreArray(data.data))); + simulate_transport(1, 2); + EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0); + + EXPECT_CALL(*this, transport_recv_frame(0, _, _)) + .With(Args<1, 2>(ElementsAreArray(data.data))); + simulate_transport(2, 3); + EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0); +} + +TEST_F(FrameRouter, first_link_sends_to_master) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(1); + router_send_frame(0, (uint8_t*)&data, 4); + EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); + + EXPECT_CALL(*this, transport_recv_frame(1, _, _)) + .With(Args<1, 2>(ElementsAreArray(data.data))); + simulate_transport(1, 0); + EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); +} + +TEST_F(FrameRouter, second_link_sends_to_master) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(2); + router_send_frame(0, (uint8_t*)&data, 4); + EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0); + + simulate_transport(2, 1); + EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); + + EXPECT_CALL(*this, transport_recv_frame(2, _, _)) + .With(Args<1, 2>(ElementsAreArray(data.data))); + simulate_transport(1, 0); + EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); + EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); +} + +TEST_F(FrameRouter, master_sends_to_master_does_nothing) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(0); + router_send_frame(0, (uint8_t*)&data, 4); + EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); +} + +TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(1); + router_send_frame(2, (uint8_t*)&data, 4); + EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); +} + +TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) { + frame_buffer_t data; + data.data = {0xAB, 0x70, 0x55, 0xBB}; + activate_router(1); + router_send_frame(0, (uint8_t*)&data, 4); + EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0); + + EXPECT_CALL(*this, transport_recv_frame(_, _, _)) + .Times(0); + activate_router(0); + receive_data(UP_LINK, + router_buffers[1].send_buffers[UP_LINK].data(), + router_buffers[1].send_buffers[UP_LINK].size()); + EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0); + EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0); +} diff --git a/quantum/serial_link/tests/frame_validator_tests.c b/quantum/serial_link/tests/frame_validator_tests.cpp index d20947e2c9..9223af83b0 100644 --- a/quantum/serial_link/tests/frame_validator_tests.c +++ b/quantum/serial_link/tests/frame_validator_tests.cpp @@ -22,24 +22,47 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <cgreen/cgreen.h> -#include <cgreen/mocks.h> -#include "serial_link/protocol/frame_validator.c" +#include "gtest/gtest.h" +#include "gmock/gmock.h" +extern "C" { +#include "serial_link/protocol/frame_validator.h" +} + +using testing::_; +using testing::ElementsAreArray; +using testing::Args; + +class FrameValidator : public testing::Test { +public: + FrameValidator() { + Instance = this; + } + + ~FrameValidator() { + Instance = nullptr; + } + + MOCK_METHOD3(route_incoming_frame, void (uint8_t link, uint8_t* data, uint16_t size)); + MOCK_METHOD3(byte_stuffer_send_frame, void (uint8_t link, uint8_t* data, uint16_t size)); + static FrameValidator* Instance; +}; + +FrameValidator* FrameValidator::Instance = nullptr; + +extern "C" { void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { - mock(data, size); + FrameValidator::Instance->route_incoming_frame(link, data, size); } void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { - mock(data, size); + FrameValidator::Instance->byte_stuffer_send_frame(link, data, size); +} } -Describe(FrameValidator); -BeforeEach(FrameValidator) {} -AfterEach(FrameValidator) {} - -Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) { - never_expect(route_incoming_frame); +TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) { + EXPECT_CALL(*this, route_incoming_frame(_, _, _)) + .Times(0); uint8_t data[] = {1, 2}; validator_recv_frame(0, 0, 1); validator_recv_frame(0, data, 2); @@ -47,55 +70,46 @@ Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) { validator_recv_frame(0, data, 4); } -Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) { +TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) { uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; - expect(route_incoming_frame, - when(size, is_equal_to(1)), - when(data, is_equal_to_contents_of(data, 1)) - ); + EXPECT_CALL(*this, route_incoming_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(data, 1))); validator_recv_frame(0, data, 5); } -Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) { +TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) { uint8_t data[] = {0x44, 0, 0, 0, 0}; - never_expect(route_incoming_frame); + EXPECT_CALL(*this, route_incoming_frame(_, _, _)) + .Times(0); validator_recv_frame(1, data, 5); } -Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) { +TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) { uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA}; - expect(route_incoming_frame, - when(size, is_equal_to(4)), - when(data, is_equal_to_contents_of(data, 4)) - ); + EXPECT_CALL(*this, route_incoming_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(data, 4))); validator_recv_frame(1, data, 8); } -Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) { +TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) { uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; - expect(route_incoming_frame, - when(size, is_equal_to(5)), - when(data, is_equal_to_contents_of(data, 5)) - ); + EXPECT_CALL(*this, route_incoming_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(data, 5))); validator_recv_frame(0, data, 9); } -Ensure(FrameValidator, sends_one_byte_with_correct_crc) { +TEST_F(FrameValidator, sends_one_byte_with_correct_crc) { uint8_t original[] = {0x44, 0, 0, 0, 0}; uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3}; - expect(byte_stuffer_send_frame, - when(size, is_equal_to(sizeof(expected))), - when(data, is_equal_to_contents_of(expected, sizeof(expected))) - ); + EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); validator_send_frame(0, original, 1); } -Ensure(FrameValidator, sends_five_bytes_with_correct_crc) { +TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) { uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0}; uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47}; - expect(byte_stuffer_send_frame, - when(size, is_equal_to(sizeof(expected))), - when(data, is_equal_to_contents_of(expected, sizeof(expected))) - ); + EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)) + .With(Args<1, 2>(ElementsAreArray(expected))); validator_send_frame(0, original, 5); } diff --git a/quantum/serial_link/tests/rules.mk b/quantum/serial_link/tests/rules.mk new file mode 100644 index 0000000000..b81515bc55 --- /dev/null +++ b/quantum/serial_link/tests/rules.mk @@ -0,0 +1,22 @@ +serial_link_byte_stuffer_SRC :=\ + $(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \ + $(SERIAL_PATH)/protocol/byte_stuffer.c + +serial_link_frame_validator_SRC := \ + $(SERIAL_PATH)/tests/frame_validator_tests.cpp \ + $(SERIAL_PATH)/protocol/frame_validator.c + +serial_link_frame_router_SRC := \ + $(SERIAL_PATH)/tests/frame_router_tests.cpp \ + $(SERIAL_PATH)/protocol/byte_stuffer.c \ + $(SERIAL_PATH)/protocol/frame_validator.c \ + $(SERIAL_PATH)/protocol/frame_router.c + +serial_link_triple_buffered_object_SRC := \ + $(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \ + $(SERIAL_PATH)/protocol/triple_buffered_object.c + +serial_link_transport_SRC := \ + $(SERIAL_PATH)/tests/transport_tests.cpp \ + $(SERIAL_PATH)/protocol/transport.c \ + $(SERIAL_PATH)/protocol/triple_buffered_object.c diff --git a/quantum/serial_link/tests/testlist.mk b/quantum/serial_link/tests/testlist.mk new file mode 100644 index 0000000000..a80e888849 --- /dev/null +++ b/quantum/serial_link/tests/testlist.mk @@ -0,0 +1,6 @@ +TEST_LIST +=\ + serial_link_byte_stuffer\ + serial_link_frame_validator\ + serial_link_frame_router\ + serial_link_triple_buffered_object\ + serial_link_transport
\ No newline at end of file diff --git a/quantum/serial_link/tests/transport_tests.c b/quantum/serial_link/tests/transport_tests.c deleted file mode 100644 index 358e1b9fd4..0000000000 --- a/quantum/serial_link/tests/transport_tests.c +++ /dev/null @@ -1,168 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2016 Fred Sundvik - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include <cgreen/cgreen.h> -#include <cgreen/mocks.h> -#include "serial_link/protocol/transport.c" -#include "serial_link/protocol/triple_buffered_object.c" - -void signal_data_written(void) { - mock(); -} - -static uint8_t sent_data[2048]; -static uint16_t sent_data_size; - -void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { - mock(destination); - memcpy(sent_data + sent_data_size, data, size); - sent_data_size += size; -} - -typedef struct { - uint32_t test; -} test_object1_t; - -typedef struct { - uint32_t test1; - uint32_t test2; -} test_object2_t; - -MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t); -MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t); -SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t); - -static remote_object_t* test_remote_objects[] = { - REMOTE_OBJECT(master_to_slave), - REMOTE_OBJECT(master_to_single_slave), - REMOTE_OBJECT(slave_to_master), -}; - -Describe(Transport); -BeforeEach(Transport) { - add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); - sent_data_size = 0; -} -AfterEach(Transport) {} - -Ensure(Transport, write_to_local_signals_an_event) { - begin_write_master_to_slave(); - expect(signal_data_written); - end_write_master_to_slave(); - begin_write_slave_to_master(); - expect(signal_data_written); - end_write_slave_to_master(); - begin_write_master_to_single_slave(1); - expect(signal_data_written); - end_write_master_to_single_slave(1); -} - -Ensure(Transport, writes_from_master_to_all_slaves) { - update_transport(); - test_object1_t* obj = begin_write_master_to_slave(); - obj->test = 5; - expect(signal_data_written); - end_write_master_to_slave(); - expect(router_send_frame, - when(destination, is_equal_to(0xFF))); - update_transport(); - transport_recv_frame(0, sent_data, sent_data_size); - test_object1_t* obj2 = read_master_to_slave(); - assert_that(obj2, is_not_equal_to(NULL)); - assert_that(obj2->test, is_equal_to(5)); -} - -Ensure(Transport, writes_from_slave_to_master) { - update_transport(); - test_object1_t* obj = begin_write_slave_to_master(); - obj->test = 7; - expect(signal_data_written); - end_write_slave_to_master(); - expect(router_send_frame, - when(destination, is_equal_to(0))); - update_transport(); - transport_recv_frame(3, sent_data, sent_data_size); - test_object1_t* obj2 = read_slave_to_master(2); - assert_that(read_slave_to_master(0), is_equal_to(NULL)); - assert_that(obj2, is_not_equal_to(NULL)); - assert_that(obj2->test, is_equal_to(7)); -} - -Ensure(Transport, writes_from_master_to_single_slave) { - update_transport(); - test_object1_t* obj = begin_write_master_to_single_slave(3); - obj->test = 7; - expect(signal_data_written); - end_write_master_to_single_slave(3); - expect(router_send_frame, - when(destination, is_equal_to(4))); - update_transport(); - transport_recv_frame(0, sent_data, sent_data_size); - test_object1_t* obj2 = read_master_to_single_slave(); - assert_that(obj2, is_not_equal_to(NULL)); - assert_that(obj2->test, is_equal_to(7)); -} - -Ensure(Transport, ignores_object_with_invalid_id) { - update_transport(); - test_object1_t* obj = begin_write_master_to_single_slave(3); - obj->test = 7; - expect(signal_data_written); - end_write_master_to_single_slave(3); - expect(router_send_frame, - when(destination, is_equal_to(4))); - update_transport(); - sent_data[sent_data_size - 1] = 44; - transport_recv_frame(0, sent_data, sent_data_size); - test_object1_t* obj2 = read_master_to_single_slave(); - assert_that(obj2, is_equal_to(NULL)); -} - -Ensure(Transport, ignores_object_with_size_too_small) { - update_transport(); - test_object1_t* obj = begin_write_master_to_slave(); - obj->test = 7; - expect(signal_data_written); - end_write_master_to_slave(); - expect(router_send_frame); - update_transport(); - sent_data[sent_data_size - 2] = 0; - transport_recv_frame(0, sent_data, sent_data_size - 1); - test_object1_t* obj2 = read_master_to_slave(); - assert_that(obj2, is_equal_to(NULL)); -} - -Ensure(Transport, ignores_object_with_size_too_big) { - update_transport(); - test_object1_t* obj = begin_write_master_to_slave(); - obj->test = 7; - expect(signal_data_written); - end_write_master_to_slave(); - expect(router_send_frame); - update_transport(); - sent_data[sent_data_size + 21] = 0; - transport_recv_frame(0, sent_data, sent_data_size + 22); - test_object1_t* obj2 = read_master_to_slave(); - assert_that(obj2, is_equal_to(NULL)); -} diff --git a/quantum/serial_link/tests/transport_tests.cpp b/quantum/serial_link/tests/transport_tests.cpp new file mode 100644 index 0000000000..21b7b165f6 --- /dev/null +++ b/quantum/serial_link/tests/transport_tests.cpp @@ -0,0 +1,188 @@ +/* +The MIT License (MIT) + +Copyright (c) 2016 Fred Sundvik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +using testing::_; +using testing::ElementsAreArray; +using testing::Args; + +extern "C" { +#include "serial_link/protocol/transport.h" +} + +struct test_object1 { + uint32_t test; +}; + +struct test_object2 { + uint32_t test1; + uint32_t test2; +}; + +MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1); +MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1); +SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1); + +static remote_object_t* test_remote_objects[] = { + REMOTE_OBJECT(master_to_slave), + REMOTE_OBJECT(master_to_single_slave), + REMOTE_OBJECT(slave_to_master), +}; + +class Transport : public testing::Test { +public: + Transport() { + Instance = this; + add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*)); + } + + ~Transport() { + Instance = nullptr; + reinitialize_serial_link_transport(); + } + + MOCK_METHOD0(signal_data_written, void ()); + MOCK_METHOD1(router_send_frame, void (uint8_t destination)); + + void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { + router_send_frame(destination); + std::copy(data, data + size, std::back_inserter(sent_data)); + } + + static Transport* Instance; + + std::vector<uint8_t> sent_data; +}; + +Transport* Transport::Instance = nullptr; + +extern "C" { +void signal_data_written(void) { + Transport::Instance->signal_data_written(); +} + +void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { + Transport::Instance->router_send_frame(destination, data, size); +} +} + +TEST_F(Transport, write_to_local_signals_an_event) { + begin_write_master_to_slave(); + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_slave(); + begin_write_slave_to_master(); + EXPECT_CALL(*this, signal_data_written()); + end_write_slave_to_master(); + begin_write_master_to_single_slave(1); + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_single_slave(1); +} + +TEST_F(Transport, writes_from_master_to_all_slaves) { + update_transport(); + test_object1* obj = begin_write_master_to_slave(); + obj->test = 5; + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_slave(); + EXPECT_CALL(*this, router_send_frame(0xFF)); + update_transport(); + transport_recv_frame(0, sent_data.data(), sent_data.size()); + test_object1* obj2 = read_master_to_slave(); + EXPECT_NE(obj2, nullptr); + EXPECT_EQ(obj2->test, 5); +} + +TEST_F(Transport, writes_from_slave_to_master) { + update_transport(); + test_object1* obj = begin_write_slave_to_master(); + obj->test = 7; + EXPECT_CALL(*this, signal_data_written()); + end_write_slave_to_master(); + EXPECT_CALL(*this, router_send_frame(0)); + update_transport(); + transport_recv_frame(3, sent_data.data(), sent_data.size()); + test_object1* obj2 = read_slave_to_master(2); + EXPECT_EQ(read_slave_to_master(0), nullptr); + EXPECT_NE(obj2, nullptr); + EXPECT_EQ(obj2->test, 7); +} + +TEST_F(Transport, writes_from_master_to_single_slave) { + update_transport(); + test_object1* obj = begin_write_master_to_single_slave(3); + obj->test = 7; + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_single_slave(3); + EXPECT_CALL(*this, router_send_frame(4)); + update_transport(); + transport_recv_frame(0, sent_data.data(), sent_data.size()); + test_object1* obj2 = read_master_to_single_slave(); + EXPECT_NE(obj2, nullptr); + EXPECT_EQ(obj2->test, 7); +} + +TEST_F(Transport, ignores_object_with_invalid_id) { + update_transport(); + test_object1* obj = begin_write_master_to_single_slave(3); + obj->test = 7; + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_single_slave(3); + EXPECT_CALL(*this, router_send_frame(4)); + update_transport(); + sent_data[sent_data.size() - 1] = 44; + transport_recv_frame(0, sent_data.data(), sent_data.size()); + test_object1* obj2 = read_master_to_single_slave(); + EXPECT_EQ(obj2, nullptr); +} + +TEST_F(Transport, ignores_object_with_size_too_small) { + update_transport(); + test_object1* obj = begin_write_master_to_slave(); + obj->test = 7; + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_slave(); + EXPECT_CALL(*this, router_send_frame(_)); + update_transport(); + sent_data[sent_data.size() - 2] = 0; + transport_recv_frame(0, sent_data.data(), sent_data.size() - 1); + test_object1* obj2 = read_master_to_slave(); + EXPECT_EQ(obj2, nullptr); +} + +TEST_F(Transport, ignores_object_with_size_too_big) { + update_transport(); + test_object1* obj = begin_write_master_to_slave(); + obj->test = 7; + EXPECT_CALL(*this, signal_data_written()); + end_write_master_to_slave(); + EXPECT_CALL(*this, router_send_frame(_)); + update_transport(); + sent_data.resize(sent_data.size() + 22); + sent_data[sent_data.size() - 1] = 0; + transport_recv_frame(0, sent_data.data(), sent_data.size()); + test_object1* obj2 = read_master_to_slave(); + EXPECT_EQ(obj2, nullptr); +} diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.c b/quantum/serial_link/tests/triple_buffered_object_tests.cpp index 6f7c82b468..7724bbee9c 100644 --- a/quantum/serial_link/tests/triple_buffered_object_tests.c +++ b/quantum/serial_link/tests/triple_buffered_object_tests.cpp @@ -22,53 +22,55 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include <cgreen/cgreen.h> -#include "serial_link/protocol/triple_buffered_object.c" +#include "gtest/gtest.h" +extern "C" { +#include "serial_link/protocol/triple_buffered_object.h" +} -typedef struct { +struct test_object{ uint8_t state; uint32_t buffer[3]; -}test_object_t; - -test_object_t test_object; +}; -Describe(TripleBufferedObject); -BeforeEach(TripleBufferedObject) { - triple_buffer_init((triple_buffer_object_t*)&test_object); -} -AfterEach(TripleBufferedObject) {} +test_object test_object; +class TripleBufferedObject : public testing::Test { +public: + TripleBufferedObject() { + triple_buffer_init((triple_buffer_object_t*)&test_object); + } +}; -Ensure(TripleBufferedObject, writes_and_reads_object) { +TEST_F(TripleBufferedObject, writes_and_reads_object) { *triple_buffer_begin_write(&test_object) = 0x3456ABCC; triple_buffer_end_write(&test_object); - assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC)); + EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC); } -Ensure(TripleBufferedObject, does_not_read_empty) { - assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); +TEST_F(TripleBufferedObject, does_not_read_empty) { + EXPECT_EQ(triple_buffer_read(&test_object), nullptr); } -Ensure(TripleBufferedObject, writes_twice_and_reads_object) { +TEST_F(TripleBufferedObject, writes_twice_and_reads_object) { *triple_buffer_begin_write(&test_object) = 0x3456ABCC; triple_buffer_end_write(&test_object); *triple_buffer_begin_write(&test_object) = 0x44778899; triple_buffer_end_write(&test_object); - assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899)); + EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899); } -Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) { +TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) { *triple_buffer_begin_write(&test_object) = 1; triple_buffer_end_write(&test_object); uint32_t* read = triple_buffer_read(&test_object); *triple_buffer_begin_write(&test_object) = 2; triple_buffer_end_write(&test_object); - assert_that(*read, is_equal_to(1)); - assert_that(*triple_buffer_read(&test_object), is_equal_to(2)); - assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); + EXPECT_EQ(*read, 1); + EXPECT_EQ(*triple_buffer_read(&test_object), 2); + EXPECT_EQ(triple_buffer_read(&test_object), nullptr); } -Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { +TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { *triple_buffer_begin_write(&test_object) = 1; triple_buffer_end_write(&test_object); uint32_t* read = triple_buffer_read(&test_object); @@ -76,7 +78,7 @@ Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) { triple_buffer_end_write(&test_object); *triple_buffer_begin_write(&test_object) = 3; triple_buffer_end_write(&test_object); - assert_that(*read, is_equal_to(1)); - assert_that(*triple_buffer_read(&test_object), is_equal_to(3)); - assert_that(triple_buffer_read(&test_object), is_equal_to(NULL)); + EXPECT_EQ(*read, 1); + EXPECT_EQ(*triple_buffer_read(&test_object), 3); + EXPECT_EQ(triple_buffer_read(&test_object), nullptr); } diff --git a/quantum/template/Makefile b/quantum/template/Makefile index 3f6d133c9b..4e2a6f00fd 100644 --- a/quantum/template/Makefile +++ b/quantum/template/Makefile @@ -1,75 +1,3 @@ - - -# MCU name -#MCU = at90usb1287 -MCU = atmega32u4 - -# Processor frequency. -# This will define a symbol, F_CPU, in all source code files equal to the -# processor frequency in Hz. You can then use this symbol in your source code to -# calculate timings. Do NOT tack on a 'UL' at the end, this will be done -# automatically to create a 32-bit value in your source code. -# -# This will be an integer division of F_USB below, as it is sourced by -# F_USB after it has run through any CPU prescalers. Note that this value -# does not *change* the processor frequency - it should merely be updated to -# reflect the processor speed set externally so that the code can use accurate -# software delays. -F_CPU = 16000000 - - -# -# LUFA specific -# -# Target architecture (see library "Board Types" documentation). -ARCH = AVR8 - -# Input clock frequency. -# This will define a symbol, F_USB, in all source code files equal to the -# input clock frequency (before any prescaling is performed) in Hz. This value may -# differ from F_CPU if prescaling is used on the latter, and is required as the -# raw input clock is fed directly to the PLL sections of the AVR for high speed -# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' -# at the end, this will be done automatically to create a 32-bit value in your -# source code. -# -# If no clock division is performed on the input clock inside the AVR (via the -# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. -F_USB = $(F_CPU) - -# Interrupt driven control endpoint task(+60) -OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT - - -# Boot Section Size in *bytes* -# Teensy halfKay 512 -# Teensy++ halfKay 1024 -# Atmel DFU loader 4096 -# LUFA bootloader 4096 -# USBaspLoader 2048 -OPT_DEFS += -DBOOTLOADER_SIZE=512 - - -# Build Options -# change yes to no to disable -# -BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) -EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) -CONSOLE_ENABLE ?= yes # Console for debug(+400) -COMMAND_ENABLE ?= yes # Commands for debug and configuration -# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE -SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend -# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work -NKRO_ENABLE ?= no # USB Nkey Rollover -BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default -MIDI_ENABLE ?= no # MIDI controls -UNICODE_ENABLE ?= no # Unicode -BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID -AUDIO_ENABLE ?= no # Audio output on port C6 - -ifndef QUANTUM_DIR +ifndef MAKEFILE_INCLUDED include ../../Makefile -endif - - +endif
\ No newline at end of file diff --git a/quantum/template/readme.md b/quantum/template/readme.md index b2fb4dd98d..b16f4cd768 100644 --- a/quantum/template/readme.md +++ b/quantum/template/readme.md @@ -3,7 +3,7 @@ ## Quantum MK Firmware -For the full Quantum feature list, see [the parent readme.md](/doc/readme.md). +For the full Quantum feature list, see [the parent readme](/). ## Building @@ -13,16 +13,16 @@ Depending on which keymap you would like to use, you will have to compile slight ### Default -To build with the default keymap, simply run `make`. +To build with the default keymap, simply run `make default`. ### Other Keymaps Several version of keymap are available in advance but you are recommended to define your favorite layout yourself. To define your own keymap create a folder with the name of your keymap in the keymaps folder, and see keymap documentation (you can find in top readme.md) and existant keymap files. -To build the firmware binary hex file with a keymap just do `make` with `keymap` option like: +To build the firmware binary hex file with a keymap just do `make` with a keymap like this: ``` -$ make keymap=[default|jack|<name>] +$ make [default|jack|<name>] ``` -Keymaps follow the format **__keymap.c__** and are stored in folders in the `keymaps` folder, eg `keymaps/my_keymap/`
\ No newline at end of file +Keymaps follow the format **__\<name\>.c__** and are stored in the `keymaps` folder. diff --git a/quantum/template/rules.mk b/quantum/template/rules.mk new file mode 100644 index 0000000000..55898147dd --- /dev/null +++ b/quantum/template/rules.mk @@ -0,0 +1,67 @@ +# MCU name +#MCU = at90usb1287 +MCU = atmega32u4 + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency in Hz. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# +# This will be an integer division of F_USB below, as it is sourced by +# F_USB after it has run through any CPU prescalers. Note that this value +# does not *change* the processor frequency - it should merely be updated to +# reflect the processor speed set externally so that the code can use accurate +# software delays. +F_CPU = 16000000 + + +# +# LUFA specific +# +# Target architecture (see library "Board Types" documentation). +ARCH = AVR8 + +# Input clock frequency. +# This will define a symbol, F_USB, in all source code files equal to the +# input clock frequency (before any prescaling is performed) in Hz. This value may +# differ from F_CPU if prescaling is used on the latter, and is required as the +# raw input clock is fed directly to the PLL sections of the AVR for high speed +# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' +# at the end, this will be done automatically to create a 32-bit value in your +# source code. +# +# If no clock division is performed on the input clock inside the AVR (via the +# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. +F_USB = $(F_CPU) + +# Interrupt driven control endpoint task(+60) +OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT + + +# Boot Section Size in *bytes* +# Teensy halfKay 512 +# Teensy++ halfKay 1024 +# Atmel DFU loader 4096 +# LUFA bootloader 4096 +# USBaspLoader 2048 +OPT_DEFS += -DBOOTLOADER_SIZE=512 + + +# Build Options +# change yes to no to disable +# +BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) +EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) +CONSOLE_ENABLE ?= yes # Console for debug(+400) +COMMAND_ENABLE ?= yes # Commands for debug and configuration +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend +# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +NKRO_ENABLE ?= no # USB Nkey Rollover +BACKLIGHT_ENABLE ?= no # Enable keyboard backlight functionality on B7 by default +MIDI_ENABLE ?= no # MIDI controls +UNICODE_ENABLE ?= no # Unicode +BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID +AUDIO_ENABLE ?= no # Audio output on port C6 |