summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_keyboard.mk8
-rw-r--r--keyboards/ergodox/keymaps/j3rn/keymap.c6
-rw-r--r--quantum/variable_trace.c110
-rw-r--r--quantum/variable_trace.h34
-rw-r--r--readme.md23
5 files changed, 178 insertions, 3 deletions
diff --git a/build_keyboard.mk b/build_keyboard.mk
index 282adcb118..61aebf3935 100644
--- a/build_keyboard.mk
+++ b/build_keyboard.mk
@@ -180,6 +180,14 @@ ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
180 VAPTH += $(SERIAL_PATH) 180 VAPTH += $(SERIAL_PATH)
181endif 181endif
182 182
183ifneq ($(strip $(VARIABLE_TRACE)),)
184 SRC += $(QUANTUM_DIR)/variable_trace.c
185 OPT_DEFS += -DNUM_TRACED_VARIABLES=$(strip $(VARIABLE_TRACE))
186ifneq ($(strip $(MAX_VARIABLE_TRACE_SIZE)),)
187 OPT_DEFS += -DMAX_VARIABLE_TRACE_SIZE=$(strip $(MAX_VARIABLE_TRACE_SIZE))
188endif
189endif
190
183# Optimize size but this may cause error "relocation truncated to fit" 191# Optimize size but this may cause error "relocation truncated to fit"
184#EXTRALDFLAGS = -Wl,--relax 192#EXTRALDFLAGS = -Wl,--relax
185 193
diff --git a/keyboards/ergodox/keymaps/j3rn/keymap.c b/keyboards/ergodox/keymaps/j3rn/keymap.c
index d913ea4a5e..2069f26ae5 100644
--- a/keyboards/ergodox/keymaps/j3rn/keymap.c
+++ b/keyboards/ergodox/keymaps/j3rn/keymap.c
@@ -16,7 +16,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
16 * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| 16 * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
17 * |Ctrl/Esc| A | S | D | F | G |------| |------| H | J | K | L | ; | ' | 17 * |Ctrl/Esc| A | S | D | F | G |------| |------| H | J | K | L | ; | ' |
18 * |--------+------+------+------+------+------| Hyper| | Meh |------+------+------+------+------+--------| 18 * |--------+------+------+------+------+------| Hyper| | Meh |------+------+------+------+------+--------|
19 * | LShift |Z/Ctrl| X | C | V | B | | | | N | M | , | . |//Ctrl| RShift | 19 * | LShift | Z | X | C | V | B | | | | N | M | , | . | / | RShift |
20 * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------' 20 * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
21 * | ~L1 | Alt |AltShf| Left | Right| | Up | Down | [ | ] | ~L1 | 21 * | ~L1 | Alt |AltShf| Left | Right| | Up | Down | [ | ] | ~L1 |
22 * `----------------------------------' `----------------------------------' 22 * `----------------------------------' `----------------------------------'
@@ -35,7 +35,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
35 KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LBRC, 35 KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LBRC,
36 KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_MINS, 36 KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_MINS,
37 CTL_T(KC_ESC), KC_A, KC_S, KC_D, KC_F, KC_G, 37 CTL_T(KC_ESC), KC_A, KC_S, KC_D, KC_F, KC_G,
38 KC_LSFT, CTL_T(KC_Z), KC_X, KC_C, KC_V, KC_B, ALL_T(KC_NO), 38 KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, ALL_T(KC_NO),
39 MO(SYMB), KC_LALT, LALT(KC_LSFT), KC_LEFT,KC_RGHT, 39 MO(SYMB), KC_LALT, LALT(KC_LSFT), KC_LEFT,KC_RGHT,
40 40
41 ALT_T(KC_APP), KC_HOME, 41 ALT_T(KC_APP), KC_HOME,
@@ -45,7 +45,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
45 KC_RBRC, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC, 45 KC_RBRC, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC,
46 KC_EQL, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS, 46 KC_EQL, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS,
47 KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, 47 KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
48 MEH_T(KC_NO),KC_N, KC_M, KC_COMM,KC_DOT, CTL_T(KC_SLSH), KC_RSFT, 48 MEH_T(KC_NO),KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_RSFT,
49 KC_UP, KC_DOWN,KC_LBRC,KC_RBRC, MO(SYMB), 49 KC_UP, KC_DOWN,KC_LBRC,KC_RBRC, MO(SYMB),
50 50
51 KC_PGUP, CTL_T(KC_ESC), 51 KC_PGUP, CTL_T(KC_ESC),
diff --git a/quantum/variable_trace.c b/quantum/variable_trace.c
new file mode 100644
index 0000000000..de580244c3
--- /dev/null
+++ b/quantum/variable_trace.c
@@ -0,0 +1,110 @@
1#include "variable_trace.h"
2#include <stddef.h>
3#include <string.h>
4
5#ifdef NO_PRINT
6#error "You need undef NO_PRINT to use the variable trace feature"
7#endif
8
9#ifndef CONSOLE_ENABLE
10#error "The console needs to be enabled in the makefile to use the variable trace feature"
11#endif
12
13
14#define NUM_TRACED_VARIABLES 1
15#ifndef MAX_VARIABLE_TRACE_SIZE
16 #define MAX_VARIABLE_TRACE_SIZE 4
17#endif
18
19typedef struct {
20 const char* name;
21 void* addr;
22 unsigned size;
23 const char* func;
24 int line;
25 uint8_t last_value[MAX_VARIABLE_TRACE_SIZE];
26
27} traced_variable_t;
28
29static traced_variable_t traced_variables[NUM_TRACED_VARIABLES];
30
31void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line) {
32 verify_traced_variables(func, line);
33 if (size > MAX_VARIABLE_TRACE_SIZE) {
34#if defined(__AVR__)
35 xprintf("Traced variable \"%S\" exceeds the maximum size %d\n", name, size);
36#else
37 xprintf("Traced variable \"%s\" exceeds the maximum size %d\n", name, size);
38#endif
39 size = MAX_VARIABLE_TRACE_SIZE;
40 }
41 int index = -1;
42 for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
43 if (index == -1 && traced_variables[i].addr == NULL){
44 index = i;
45 }
46 else if (strcmp_P(name, traced_variables[i].name)==0) {
47 index = i;
48 break;
49 }
50 }
51
52 if (index == -1) {
53 xprintf("You can only trace %d variables at the same time\n", NUM_TRACED_VARIABLES);
54 return;
55 }
56
57 traced_variable_t* t = &traced_variables[index];
58 t->name = name;
59 t->addr = addr;
60 t->size = size;
61 t->func = func;
62 t->line = line;
63 memcpy(&t->last_value[0], addr, size);
64
65}
66
67void remove_traced_variable(const char* name, const char* func, int line) {
68 verify_traced_variables(func, line);
69 for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
70 if (strcmp_P(name, traced_variables[i].name)==0) {
71 traced_variables[i].name = 0;
72 traced_variables[i].addr = NULL;
73 break;
74 }
75 }
76}
77
78void verify_traced_variables(const char* func, int line) {
79 for (int i = 0; i < NUM_TRACED_VARIABLES; i++) {
80 traced_variable_t* t = &traced_variables[i];
81 if (t->addr != NULL && t->name != NULL) {
82 if (memcmp(t->last_value, t->addr, t->size)!=0){
83#if defined(__AVR__)
84 xprintf("Traced variable \"%S\" has been modified\n", t->name);
85 xprintf("Between %S:%d\n", t->func, t->line);
86 xprintf("And %S:%d\n", func, line);
87
88#else
89 xprintf("Traced variable \"%s\" has been modified\n", t->name);
90 xprintf("Between %s:%d\n", t->func, t->line);
91 xprintf("And %s:%d\n", func, line);
92#endif
93 xprintf("Previous value ");
94 for (int j=0; j<t->size;j++) {
95 print_hex8(t->last_value[j]);
96 }
97 xprintf("\nNew value ");
98 uint8_t* addr = (uint8_t*)(t->addr);
99 for (int j=0; j<t->size;j++) {
100 print_hex8(addr[j]);
101 }
102 xprintf("\n");
103 memcpy(t->last_value, addr, t->size);
104 }
105 }
106
107 t->func = func;
108 t->line = line;
109 }
110}
diff --git a/quantum/variable_trace.h b/quantum/variable_trace.h
new file mode 100644
index 0000000000..46bd827861
--- /dev/null
+++ b/quantum/variable_trace.h
@@ -0,0 +1,34 @@
1#ifndef VARIABLE_TRACE_H
2#define VARIABLE_TRACE_H
3
4// For more information about the variable tracing see the readme.
5
6#include "print.h"
7
8#ifdef NUM_TRACED_VARIABLES
9
10// Start tracing a variable at the memory address addr
11// The name can be anything and is used only for reporting
12// The size should usually be the same size as the variable you are interested in
13#define ADD_TRACED_VARIABLE(name, addr, size) \
14 add_traced_variable(PSTR(name), (void*)addr, size, PSTR(__FILE__), __LINE__)
15
16// Stop tracing the variable with the given name
17#define REMOVE_TRACED_VARIABLE(name) remove_traced_variable(PSTR(name), PSTR(__FILE__), __LINE__)
18
19// Call to get messages when the variable has been changed
20#define VERIFY_TRACED_VARIABLES() verify_traced_variables(PSTR(__FILE__), __LINE__)
21
22#else
23
24#define ADD_TRACED_VARIABLE(name, addr, size)
25#define REMOVE_TRACED_VARIABLE(name)
26#define VERIFY_TRACED_VARIABLES()
27
28#endif
29
30// Don't call directly, use the macros instead
31void add_traced_variable(const char* name, void* addr, unsigned size, const char* func, int line);
32void remove_traced_variable(const char* name, const char* func, int line);
33void verify_traced_variables(const char* func, int line);
34#endif
diff --git a/readme.md b/readme.md
index 95c6a5a0b9..8615b48d55 100644
--- a/readme.md
+++ b/readme.md
@@ -344,6 +344,10 @@ This allows you to interface with a Bluefruit EZ-key to send keycodes wirelessly
344 344
345This allows you output audio on the C6 pin (needs abstracting). See the [audio section](#driving-a-speaker---audio-support) for more information. 345This allows you output audio on the C6 pin (needs abstracting). See the [audio section](#driving-a-speaker---audio-support) for more information.
346 346
347`VARIABLE_TRACE`
348
349Use this to debug changes to variable values, see the [tracing variables](#tracing-variables) section for more information.
350
347### Customizing Makefile options on a per-keymap basis 351### Customizing Makefile options on a per-keymap basis
348 352
349If your keymap directory has a file called `Makefile` (note the filename), any Makefile options you set in that file will take precedence over other Makefile options for your particular keyboard. 353If your keymap directory has a file called `Makefile` (note the filename), any Makefile options you set in that file will take precedence over other Makefile options for your particular keyboard.
@@ -1284,3 +1288,22 @@ If there are problems with the tests, you can find the executable in the `./buil
1284It's not yet possible to do a full integration test, where you would compile the whole firmware and define a keymap that you are going to test. However there are plans for doing that, because writing tests that way would probably be easier, at least for people that are not used to unit testing. 1288It's not yet possible to do a full integration test, where you would compile the whole firmware and define a keymap that you are going to test. However there are plans for doing that, because writing tests that way would probably be easier, at least for people that are not used to unit testing.
1285 1289
1286In that model you would emulate the input, and expect a certain output from the emulated keyboard. 1290In that model you would emulate the input, and expect a certain output from the emulated keyboard.
1291
1292# Tracing variables
1293
1294Sometimes you might wonder why a variable gets changed and where, and this can be quite tricky to track down without having a debugger. It's of course possible to manually add print statements to track it, but you can also enable the variable trace feature. This works for both for variables that are changed by the code, and when the variable is changed by some memory corruption.
1295
1296To take the feature into use add `VARIABLE_TRACE=x` to the end of you make command. `x` represents the number of variables you want to trace, which is usually 1.
1297
1298Then at a suitable place in the code, call `ADD_TRACED_VARIABLE`, to begin the tracing. For example to trace all the layer changes, you can do this
1299```c
1300void matrix_init_user(void) {
1301 ADD_TRACED_VARIABLE("layer", &layer_state, sizeof(layer_state));
1302}
1303```
1304
1305This will add a traced variable named "layer" (the name is just for your information), which tracks the memory location of `layer_state`. It tracks 4 bytes (the size of `layer_state`), so any modification to the variable will be reported. By default you can not specify a size bigger than 4, but you can change it by adding `MAX_VARIABLE_TRACE_SIZE=x` to the end of the make command line.
1306
1307In order to actually detect changes to the variables you should call `VERIFY_TRACED_VARIABLES` around the code that you think that modifies the variable. If a variable is modified it will tell you between which two `VERIFY_TRACED_VARIABLES` calls the modification happened. You can then add more calls to track it down further. I don't recommend spamming the codebase with calls. It's better to start with a few, and then keep adding them in a binary search fashion. You can also delete the ones you don't need, as each call need to store the file name and line number in the ROM, so you can run out of memory if you add too many calls.
1308
1309Also remember to delete all the tracing code ones you have found the bug, as you wouldn't want to create a pull request with tracing code. \ No newline at end of file