aboutsummaryrefslogtreecommitdiffstats
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/config_common.h9
-rw-r--r--quantum/dynamic_macro.h226
-rw-r--r--quantum/keycode_config.h5
-rw-r--r--quantum/keymap.h23
-rw-r--r--quantum/keymap_extras/keymap_canadian_multilingual.h255
-rw-r--r--quantum/keymap_extras/keymap_dvorak.h4
-rw-r--r--quantum/process_keycode/process_tap_dance.c132
-rw-r--r--quantum/process_keycode/process_tap_dance.h19
-rw-r--r--quantum/process_keycode/process_unicode.c213
-rw-r--r--quantum/process_keycode/process_unicode.h41
-rw-r--r--quantum/quantum.c173
-rw-r--r--quantum/quantum.h3
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c3
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.h3
-rw-r--r--quantum/serial_link/protocol/transport.c4
-rw-r--r--quantum/serial_link/protocol/transport.h7
-rw-r--r--quantum/serial_link/tests/byte_stuffer_tests.cpp (renamed from quantum/serial_link/tests/byte_stuffer_tests.c)313
-rw-r--r--quantum/serial_link/tests/frame_router_tests.c231
-rw-r--r--quantum/serial_link/tests/frame_router_tests.cpp229
-rw-r--r--quantum/serial_link/tests/frame_validator_tests.cpp (renamed from quantum/serial_link/tests/frame_validator_tests.c)90
-rw-r--r--quantum/serial_link/tests/rules.mk22
-rw-r--r--quantum/serial_link/tests/testlist.mk6
-rw-r--r--quantum/serial_link/tests/transport_tests.c168
-rw-r--r--quantum/serial_link/tests/transport_tests.cpp188
-rw-r--r--quantum/serial_link/tests/triple_buffered_object_tests.cpp (renamed from quantum/serial_link/tests/triple_buffered_object_tests.c)52
-rw-r--r--quantum/template/Makefile76
-rw-r--r--quantum/template/readme.md10
-rw-r--r--quantum/template/rules.mk67
28 files changed, 1691 insertions, 881 deletions
diff --git a/quantum/config_common.h b/quantum/config_common.h
index 09a4fe701..8ed5f4a10 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 000000000..a3ad61bc7
--- /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.
+ *
+ * &macro_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(&macro_pointer, macro_buffer);
+ macro_id = 1;
+ return false;
+ case DYN_REC_START2:
+ dynamic_macro_record_start(&macro_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, &macro_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(&macro_pointer, r_macro_end, +1, record);
+ break;
+ case 2:
+ dynamic_macro_record_key(&macro_pointer, macro_end, -1, record);
+ break;
+ }
+ return true;
+ break;
+ }
+ }
+
+ return true;
+}
+
+#endif
diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h
index 6216eefc9..c15b0d32f 100644
--- a/quantum/keycode_config.h
+++ b/quantum/keycode_config.h
@@ -1,6 +1,9 @@
#include "eeconfig.h"
#include "keycode.h"
+#ifndef KEYCODE_CONFIG_H
+#define KEYCODE_CONFIG_H
+
uint16_t keycode_config(uint16_t keycode);
/* NOTE: Not portable. Bit field order depends on implementation */
@@ -19,3 +22,5 @@ typedef union {
} keymap_config_t;
extern keymap_config_t keymap_config;
+
+#endif /* KEYCODE_CONFIG_H */
diff --git a/quantum/keymap.h b/quantum/keymap.h
index a15865183..98ddfd0c5 100644
--- a/quantum/keymap.h
+++ b/quantum/keymap.h
@@ -111,6 +111,7 @@ enum quantum_keycodes {
MAGIC_UNSWAP_BACKSLASH_BACKSPACE,
MAGIC_UNHOST_NKRO,
MAGIC_UNSWAP_ALT_GUI,
+ MAGIC_TOGGLE_NKRO,
// Leader key
#ifndef DISABLE_LEADER
@@ -156,16 +157,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 +310,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/keymap_extras/keymap_canadian_multilingual.h b/quantum/keymap_extras/keymap_canadian_multilingual.h
new file mode 100644
index 000000000..0bc20c7b9
--- /dev/null
+++ b/quantum/keymap_extras/keymap_canadian_multilingual.h
@@ -0,0 +1,255 @@
+#ifndef KEYMAP_CANADIAN_MULTILINGUAG_H
+#define KEYMAP_CANADIAN_MULTILINGUAG_H
+
+#include "keymap.h"
+
+// Alt gr
+#ifndef ALTGR
+#define ALTGR(kc) RALT(kc)
+#endif
+#ifndef ALGR
+#define ALGR(kc) ALTGR(kc)
+#endif
+
+#define CSA_ALTGR KC_RALT
+#define CSA_ALGR CSA_ALTGR
+
+#ifndef GR2A
+#define GR2A(kc) RCTL(kc)
+#endif
+
+// Normal characters
+// First row
+#define CSA_SLASH KC_GRV // /
+#define CSA_SLSH CSA_SLASH
+
+// Second row
+#define CSA_DEAD_CIRCUMFLEX KC_LBRACKET // dead ^
+#define CSA_DCRC CSA_DEAD_CIRCUMFLEX
+#define CSA_C_CEDILLA KC_RBRACKET // Ç
+#define CSA_CCED CSA_C_CEDILLA
+
+// Third row
+#define CSA_E_GRAVE KC_QUOT // è
+#define CSA_EGRV CSA_E_GRAVE
+#define CSA_A_GRAVE KC_BSLASH // à
+#define CSA_AGRV CSA_A_GRAVE
+
+// Fourth row
+#define CSA_U_GRAVE KC_NONUS_BSLASH // ù
+#define CSA_UGRV CSA_U_GRAVE
+#define CSA_E_ACUTE KC_SLSH // é
+#define CSA_ECUT CSA_E_ACUTE
+
+// Shifted characters
+// First row
+#define CSA_BACKSLASH LSFT(CSA_SLASH) /* \ */
+#define CSA_BSLS CSA_BACKSLASH
+#define CSA_QUESTION LSFT(KC_6) // ?
+#define CSA_QEST CSA_QUESTION
+
+// Second row
+#define CSA_DEAD_TREMA LSFT(CSA_DEAD_CIRCUMFLEX) // dead trema/umlaut/diaresis for ä ë ï ö ü
+#define CSA_DTRM CSA_DEAD_TREMA
+
+// Third row
+// all same as US-QWERTY, or capitalised character of the non-shifted key
+
+// Fourth row
+#define CSA_APOSTROPHE LSFT(KC_COMMA) // '
+#define CSA_APOS CSA_APOSTROPHE
+#define CSA_DOUBLE_QUOTE LSFT(KC_DOT) // "
+#define CSA_DQOT CSA_DOUBLE_QUOTE
+
+// Alt Gr-ed characters
+// First row
+#define CSA_PIPE ALTGR(CSA_SLASH) // |
+#define CSA_CURRENCY ALTGR(KC_4) // ¤
+#define CSA_CURR CSA_CURRENCY
+#define CSA_LEFT_CURLY_BRACE ALTGR(KC_7) // {
+#define CSA_LCBR CSA_LEFT_CURLY_BRACE
+#define CSA_RIGHT_CURLY_BRACE ALTGR(KC_8) // }
+#define CSA_RCBR CSA_RIGHT_CURLY_BRACE
+#define CSA_LBRACKET ALTGR(KC_9) // [
+#define CSA_LBRC CSA_LBRACKET
+#define CSA_RBRACKET ALTGR(KC_0) // ]
+#define CSA_RBRC CSA_RBRACKET
+#define CSA_NEGATION ALTGR(KC_EQUAL) // ¬
+#define CSA_NEGT CSA_NEGATION
+
+// Second row
+// euro symbol not available on Linux? (X.org)
+#define CSA_EURO ALTGR(KC_E) // €
+#define CSA_DEAD_GRAVE ALTGR(CSA_DEAD_CIRCUMFLEX)
+#define CSA_DGRV CSA_DEAD_GRAVE // dead `
+#define CSA_DEAD_TILDE ALTGR(CSA_C_CEDILLA) // ~
+#define CSA_DTLD CSA_DEAD_TILDE
+
+// Third row
+#define CSA_DEGREE ALTGR(KC_SCOLON) // °
+#define CSA_DEGR CSA_DEGREE
+
+// Fourth row
+#define CSA_LEFT_GUILLEMET ALTGR(KC_Z) // «
+#define CSA_LGIL CSA_LEFT_GUILLEMET
+#define CSA_RIGHT_GUILLEMET ALTGR(KC_X) // »
+#define CSA_RGIL CSA_RIGHT_GUILLEMET
+#define CSA_LESS ALTGR(KC_COMMA) // <
+#define CSA_GREATER ALTGR(KC_DOT) // >
+#define CSA_GRTR CSA_GREATER
+
+// Space bar
+#define CSA_NON_BREAKING_SPACE ALTGR(KC_SPACE)
+#define CSA_NBSP CSA_NON_BREAKING_SPACE
+
+// GR2A-ed characters
+// First row
+#define CSA_SUPERSCRIPT_ONE GR2A(KC_1) // ¹
+#define CSA_SUP1 CSA_SUPERSCRIPT_ONE
+#define CSA_SUPERSCRIPT_TWO GR2A(KC_2) // ²
+#define CSA_SUP2 CSA_SUPERSCRIPT_TWO
+#define CSA_SUPERSCRIPT_THREE GR2A(KC_3) // ³
+#define CSA_SUP3 CSA_SUPERSCRIPT_THREE
+#define CSA_ONE_QUARTER GR2A(KC_4) // ¼
+#define CSA_1QRT CSA_ONE_QUARTER
+#define CSA_ONE_HALF GR2A(KC_5) // ½
+#define CSA_1HLF CSA_ONE_HALF
+#define CSA_THREE_QUARTERS GR2A(KC_6) // ¾
+#define CSA_3QRT CSA_THREE_QUARTERS
+// nothing on 7-0 and -
+#define CSA_DEAD_CEDILLA GR2A(KC_EQUAL) // dead ¸
+#define CSA_DCED CSA_DEAD_CEDILLA
+
+// Second row
+#define CSA_OMEGA GR2A(KC_Q) // ω
+#define CSA_OMEG CSA_OMEGA
+#define CSA_L_STROKE GR2A(KC_W) // ł
+#define CSA_LSTK CSA_L_STROKE
+#define CSA_OE_LIGATURE GR2A(KC_E) // œ
+#define CSA_OE CSA_OE_LIGATURE
+#define CSA_PARAGRAPH GR2A(KC_R) // ¶
+#define CSA_PARG CSA_PARAGRAPH
+#define CSA_T_STROKE GR2A(KC_T) // ŧ
+#define CSA_LEFT_ARROW GR2A(KC_Y) // ←
+#define CSA_LARW CSA_LEFT_ARROW
+#define CSA_DOWN_ARROW GR2A(KC_U) // ↓
+#define CSA_DARW CSA_DOWN_ARROW
+#define CSA_RIGHT_ARROW GR2A(KC_I) // →
+#define CSA_RARW CSA_RIGHT_ARROW
+#define CSA_O_STROKE GR2A(KC_O) // ø
+#define CSA_OSTK CSA_O_STROKE
+#define CSA_THORN GR2A(KC_P) // þ
+#define CSA_THRN CSA_THORN
+// nothing on ^
+#define CSA_TILDE GR2A(CSA_C_CEDILLA) // dead ~
+#define CSA_TILD CSA_TILDE
+
+// Third row
+#define CSA_AE_LIGATURE GR2A(KC_A) // æ
+#define CSA_AE CSA_AE_LIGATURE
+#define CSA_SHARP_S GR2A(KC_S) // ß
+#define CSA_SRPS CSA_SHARP_S
+#define CSA_ETH GR2A(KC_D) // ð
+// nothing on F
+#define CSA_ENG GR2A(KC_G) // ŋ
+#define CSA_H_SRTOKE GR2A(KC_H) // ħ
+#define CSA_HSTK CSA_H_SRTOKE
+#define CSA_IJ_LIGATURE GR2A(KC_J) // ij
+#define CSA_IJ CSA_IJ_LIGATURE
+#define CSA_KRA GR2A(KC_K) // ĸ
+#define CSA_L_FLOWN_DOT GR2A(KC_L) // ŀ
+#define CSA_LFLD CSA_L_FLOWN_DOT
+#define CSA_DEAD_ACUTE GR2A(KC_SCLN) // dead acute accent
+#define CSA_DACT CSA_DEAD_ACUTE
+// nothing on È & À
+
+// Fourth row
+#define CSA_CENT GR2A(KC_C) // ¢
+#define CSA_LEFT_DOUBLE_QUOTE GR2A(KC_V) // “
+#define CSA_LDQT CSA_LEFT_DOUBLE_QUOTE
+#define CSA_RIGHT_DOUBLE_QUOTE GR2A(KC_B) // ”
+#define CSA_RDQT CSA_RIGHT_DOUBLE_QUOTE
+#define CSA_N_APOSTROPHE GR2A(KC_N) // ʼn (deprecated unicode codepoint)
+#define CSA_NAPO CSA_N_APOSTROPHE
+#define CSA_MU GR2A(KC_M) // μ
+#define CSA_HORIZONTAL_BAR GR2A(KC_COMMA) // ―
+#define CSA_HZBR CSA_HORIZONTAL_BAR
+#define CSA_DEAD_DOT_ABOVE GR2A(KC_DOT) // dead ˙
+#define CSA_DDTA CSA_DEAD_DOT_ABOVE
+
+// GR2A-shifted characters (different from capitalised GR2A-ed characters)
+// First row
+#define CSA_SOFT_HYPHEN GR2A(LSFT(CSA_SLASH)) // soft-hyphen, appears as a hyphen in wrapped word
+#define CSA_SHYP CSA_SOFT_HYPHEN
+#define CSA_INVERTED_EXCLAIM GR2A(KC_EXCLAIM) // ¡
+#define CSA_IXLM CSA_INVERTED_EXCLAIM
+// nothing on 2
+#define CSA_POUND GR2A(LSFT(KC_3)) // £
+#define CSA_GBP CSA_POUND_SIGN
+// already on ALTGR(KC_E)
+#define CSA_EURO_BIS GR2A(LSFT(KC_4)) // €
+#define CSA_EURB CSA_EURO_BIS
+#define CSA_THREE_EIGHTHS GR2A(LSFT(KC_5)) // ⅜
+#define CSA_3ON8 CSA_THREE_EIGHTHS
+#define CSA_FIVE_EIGHTHS GR2A(LSFT(KC_6)) // ⅝
+#define CSA_5ON8 CSA_FIVE_EIGHTHS
+#define CSA_SEVEN_EIGHTHS GR2A(LSFT(KC_7)) // ⅞
+#define CSA_7ON8 CSA_SEVEN_EIGHTHS
+#define CSA_TRADEMARK GR2A(LSFT(KC_8)) // ™
+#define CSA_TM CSA_TRADEMARK
+#define CSA_PLUS_MINUS GR2A(LSFT(KC_9)) // ±
+#define CSA_PSMS CSA_PLUS_MINUS
+// nothing on 0
+#define CSA_INVERTED_QUESTION GR2A(LSFT(KC_MINUS)) // ¿
+#define CSA_IQST CSA_INVERTED_QUESTION
+#define CSA_DEAD_OGONEK GR2A(LSFT(KC_EQUAL)) // dead ˛
+#define CSA_DOGO CSA_DEAD_OGONEK
+
+// Second row
+#define CSA_REGISTERED_TRADEMARK GR2A(LSFT(KC_R)) // ®
+#define CSA_RTM CSA_REGISTERED_TRADEMARK
+#define CSA_YEN GR2A(LSFT(KC_Y)) // ¥
+#define CSA_YUAN CSA_YEN
+#define CSA_UP_ARROW LSFT(CSA_DOWN_ARROW) // ↑
+#define CSA_DOTLESS_I GR2A(LSFT(KC_I)) // ı
+#define CSA_DLSI CSA_DOTLESS_I
+#define CSA_DEAD_RING GR2A(LSFT(CSA_DCRC)) // dead °
+#define CSA_DRNG CSA_DEAD_RING
+#define CSA_DEAD_MACRON GR2A(LSFT(CSA_C_CEDILLA)) // dead ¯
+#define CSA_DMCR CSA_DEAD_MACRON
+
+// Third row
+#define CSA_SECTION GR2A(LSFT(KC_S)) // §
+#define CSA_SECT CSA_SECTION
+#define CSA_ORDINAL_INDICATOR_A GR2A(LSFT(KC_F)) // ª
+#define CSA_ORDA CSA_ORDINAL_INDICATOR_A
+#define CSA_DEAD_DOUBLE_ACUTE LSFT(CSA_DEAD_ACUTE) // ˝
+#define CSA_DDCT CSA_DEAD_DOUBLE_ACUTE
+#define CSA_DEAD_CARON GR2A(LSFT(CSA_E_GRAVE)) // dead ˇ
+#define CSA_DCAR CSA_DEAD_CARON
+#define CSA_DEAD_BREVE GR2A(LSFT(CSA_A_GRAVE)) // dead ˘
+#define CSA_DBRV CSA_DEAD_BREVE
+
+// Fourth row
+#define CSA_BROKEN_PIPE GR2A(LSFT(CSA_U_GRAVE)) // ¦
+#define CSA_BPIP CSA_BROKEN_PIPE
+#define CSA_COPYRIGHT GR2A(LSFT(KC_C)) // ©
+#define CSA_CPRT CSA_COPYRIGHT
+#define CSA_LEFT_QUOTE GR2A(LSFT(KC_V)) // ‘
+#define CSA_LQOT CSA_LEFT_QUOTE
+#define CSA_RIGHT_QUOTE GR2A(LSFT(KC_B)) // ’
+#define CSA_RQOT CSA_RIGHT_QUOTE
+#define CSA_EIGHTH_NOTE GR2A(LSFT(KC_N)) // ♪
+#define CSA_8NOT CSA_EIGHTH_NOTE
+#define CSA_ORDINAL_INDICATOR_O GR2A(LSFT(KC_M)) // º
+#define CSA_ORDO CSA_ORDINAL_INDICATOR_O
+#define CSA_TIMES GR2A(LSFT(KC_COMMA)) // ×
+#define CSA_TIMS CSA_TIMES
+#define CSA_OBELUS GR2A(LSFT(KC_DOT)) // ÷
+#define CSA_OBEL CSA_OBELUS
+// more conventional name of the symbol
+#define CSA_DIVISION_SIGN CSA_OBELUS
+#define CSA_DVSN CSA_DIVISION_SIGN
+// TODO GR2A(LSFT(CSA_E_ACUTE))
+
+#endif
diff --git a/quantum/keymap_extras/keymap_dvorak.h b/quantum/keymap_extras/keymap_dvorak.h
index 17f205977..a0feed850 100644
--- a/quantum/keymap_extras/keymap_dvorak.h
+++ b/quantum/keymap_extras/keymap_dvorak.h
@@ -70,6 +70,10 @@
#define DV_LCBR LSFT(DV_LBRC)
#define DV_RCBR LSFT(DV_RBRC)
+#define DV_DQUO LSFT(DV_QUOT)
+#define DV_LABK LSFT(DV_COMM)
+#define DV_RABK LSFT(DV_DOT)
+
#define DV_QUES LSFT(DV_SLSH)
#define DV_PLUS LSFT(DV_EQL)
#define DV_PIPE LSFT(DV_BSLS)
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 5429e3438..6ae362c4c 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,119 @@ 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];
+ if ((int16_t)idx > highest_td)
+ highest_td = idx;
+ 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;
- }
-
- qk_tap_dance_state.active = true;
- qk_tap_dance_state.pressed = record->event.pressed;
+ 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.keycode = keycode;
+ action->state.count++;
+ action->state.timer = timer_read();
+ process_tap_dance_action_on_each_tap (action);
+
+ 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;
- process_tap_dance_action_on_each_tap (action);
+ if (highest_td == -1)
+ return true;
+
+ 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;
- process_tap_dance_action_on_dance_finished (action);
- reset_tap_dance (&qk_tap_dance_state);
+ for (int i = 0; i <= highest_td; i++) {
+ qk_tap_dance_action_t *action = &tap_dance_actions[i];
+
+ 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 6a1258067..f753cbba6 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;
@@ -37,19 +39,20 @@ typedef struct
#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \
.fn = { NULL, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset }, \
- .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }) \
+ .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }), \
}
#define ACTION_TAP_DANCE_FN(user_fn) { \
- .fn = { NULL, user_fn, NULL } \
+ .fn = { NULL, user_fn, NULL }, \
+ .user_data = NULL, \
}
-#define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_reset) { \
- .fn = { user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_reset } \
+#define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset) { \
+ .fn = { user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset }, \
+ .user_data = NULL, \
}
-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 ad5d7f86b..a5d7dca21 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 ca17f8f66..27f8072ee 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 bc2da510f..a16bd5443 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;
}
@@ -157,7 +199,7 @@ bool process_record_quantum(keyrecord_t *record) {
return false;
break;
#endif
- case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_UNSWAP_ALT_GUI:
+ case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_NKRO:
if (record->event.pressed) {
// MAGIC actions (BOOTMAGIC without the boot)
if (!eeconfig_is_enabled()) {
@@ -165,48 +207,73 @@ bool process_record_quantum(keyrecord_t *record) {
}
/* keymap config */
keymap_config.raw = eeconfig_read_keymap();
- if (keycode == MAGIC_SWAP_CONTROL_CAPSLOCK) {
- keymap_config.swap_control_capslock = 1;
- } else if (keycode == MAGIC_CAPSLOCK_TO_CONTROL) {
- keymap_config.capslock_to_control = 1;
- } else if (keycode == MAGIC_SWAP_LALT_LGUI) {
- keymap_config.swap_lalt_lgui = 1;
- } else if (keycode == MAGIC_SWAP_RALT_RGUI) {
- keymap_config.swap_ralt_rgui = 1;
- } else if (keycode == MAGIC_NO_GUI) {
- keymap_config.no_gui = 1;
- } else if (keycode == MAGIC_SWAP_GRAVE_ESC) {
- keymap_config.swap_grave_esc = 1;
- } else if (keycode == MAGIC_SWAP_BACKSLASH_BACKSPACE) {
- keymap_config.swap_backslash_backspace = 1;
- } else if (keycode == MAGIC_HOST_NKRO) {
- keymap_config.nkro = 1;
- } else if (keycode == MAGIC_SWAP_ALT_GUI) {
- keymap_config.swap_lalt_lgui = 1;
- keymap_config.swap_ralt_rgui = 1;
- }
- /* UNs */
- else if (keycode == MAGIC_UNSWAP_CONTROL_CAPSLOCK) {
- keymap_config.swap_control_capslock = 0;
- } else if (keycode == MAGIC_UNCAPSLOCK_TO_CONTROL) {
- keymap_config.capslock_to_control = 0;
- } else if (keycode == MAGIC_UNSWAP_LALT_LGUI) {
- keymap_config.swap_lalt_lgui = 0;
- } else if (keycode == MAGIC_UNSWAP_RALT_RGUI) {
- keymap_config.swap_ralt_rgui = 0;
- } else if (keycode == MAGIC_UNNO_GUI) {
- keymap_config.no_gui = 0;
- } else if (keycode == MAGIC_UNSWAP_GRAVE_ESC) {
- keymap_config.swap_grave_esc = 0;
- } else if (keycode == MAGIC_UNSWAP_BACKSLASH_BACKSPACE) {
- keymap_config.swap_backslash_backspace = 0;
- } else if (keycode == MAGIC_UNHOST_NKRO) {
- keymap_config.nkro = 0;
- } else if (keycode == MAGIC_UNSWAP_ALT_GUI) {
- keymap_config.swap_lalt_lgui = 0;
- keymap_config.swap_ralt_rgui = 0;
+ switch (keycode)
+ {
+ case MAGIC_SWAP_CONTROL_CAPSLOCK:
+ keymap_config.swap_control_capslock = true;
+ break;
+ case MAGIC_CAPSLOCK_TO_CONTROL:
+ keymap_config.capslock_to_control = true;
+ break;
+ case MAGIC_SWAP_LALT_LGUI:
+ keymap_config.swap_lalt_lgui = true;
+ break;
+ case MAGIC_SWAP_RALT_RGUI:
+ keymap_config.swap_ralt_rgui = true;
+ break;
+ case MAGIC_NO_GUI:
+ keymap_config.no_gui = true;
+ break;
+ case MAGIC_SWAP_GRAVE_ESC:
+ keymap_config.swap_grave_esc = true;
+ break;
+ case MAGIC_SWAP_BACKSLASH_BACKSPACE:
+ keymap_config.swap_backslash_backspace = true;
+ break;
+ case MAGIC_HOST_NKRO:
+ keymap_config.nkro = true;
+ break;
+ case MAGIC_SWAP_ALT_GUI:
+ keymap_config.swap_lalt_lgui = true;
+ keymap_config.swap_ralt_rgui = true;
+ break;
+ case MAGIC_UNSWAP_CONTROL_CAPSLOCK:
+ keymap_config.swap_control_capslock = false;
+ break;
+ case MAGIC_UNCAPSLOCK_TO_CONTROL:
+ keymap_config.capslock_to_control = false;
+ break;
+ case MAGIC_UNSWAP_LALT_LGUI:
+ keymap_config.swap_lalt_lgui = false;
+ break;
+ case MAGIC_UNSWAP_RALT_RGUI:
+ keymap_config.swap_ralt_rgui = false;
+ break;
+ case MAGIC_UNNO_GUI:
+ keymap_config.no_gui = false;
+ break;
+ case MAGIC_UNSWAP_GRAVE_ESC:
+ keymap_config.swap_grave_esc = false;
+ break;
+ case MAGIC_UNSWAP_BACKSLASH_BACKSPACE:
+ keymap_config.swap_backslash_backspace = false;
+ break;
+ case MAGIC_UNHOST_NKRO:
+ keymap_config.nkro = false;
+ break;
+ case MAGIC_UNSWAP_ALT_GUI:
+ keymap_config.swap_lalt_lgui = false;
+ keymap_config.swap_ralt_rgui = false;
+ break;
+ case MAGIC_TOGGLE_NKRO:
+ keymap_config.nkro = !keymap_config.nkro;
+ break;
+ default:
+ break;
}
eeconfig_update_keymap(keymap_config.raw);
+ clear_keyboard(); // clear to prevent stuck keys
+
return false;
}
break;
@@ -229,7 +296,7 @@ bool process_record_quantum(keyrecord_t *record) {
unregister_mods(MOD_BIT(KC_LSFT));
}
return false;
- break;
+ // break;
}
case KC_RSPC: {
@@ -251,7 +318,7 @@ bool process_record_quantum(keyrecord_t *record) {
unregister_mods(MOD_BIT(KC_RSFT));
}
return false;
- break;
+ // break;
}
default: {
shift_interrupted[0] = true;
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 6e3fbcc79..0c6046649 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 fb4c45a8d..2c87d64c2 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 2cc88beb4..97e896856 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 f418d11ce..ff795fe20 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 9a052d880..2c5d890b2 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 64b170e8c..ff49d727b 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 6c806fa93..000000000
--- 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 = &current_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 000000000..2bd5bf830
--- /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 d20947e2c..9223af83b 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 000000000..b81515bc5
--- /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 000000000..a80e88884
--- /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 358e1b9fd..000000000
--- 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 000000000..21b7b165f
--- /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 6f7c82b46..7724bbee9 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 3f6d133c9..4e2a6f00f 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 b2fb4dd98..b16f4cd76 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 000000000..55898147d
--- /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