-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdactyl.ino
205 lines (181 loc) · 5.46 KB
/
dactyl.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// switch between keyboards with this one
//#define REGULAR
#define TEST_BOARD
// useful if you have more than one half to a keyboard
// intentionally defined to allow users to use only the arduino and remove any code/memory usage from using mcp io expander
#ifdef REGULAR
#define IO_EXPANDER
#endif // REGULAR
// debug flag, call log() as you would serial.printf
// when debug is undefined, log() will turn into an empty inline method and the compiler will remove 3kb of debug code+strings from memory
#define DEBUG true
//#define VERBOSE
#ifdef DEBUG
// features that depend on debug to work anyway
// key release log
//#define DEBUG_RELEASE
// how long it takes to run each loop and how much memory is currently between heap and stack
#define LOOPTIMER
#endif // DEBUG
// wdt_enable in loop() will prevent the system from being reprogrammed without a reset
// this is useful for production applications but can be annoying when debugging
// when enabled, removing the connection between two boards when the io expander is enabled can be used to halt the board in a startup loop
// debug disables this to make it easy to program
// remember not to spend more than 250ms thinking in the processing loop or *boom*
#ifndef DEBUG
#ifdef IO_EXPANDER
#ifdef REGULAR
#define WATCHDOG_ENABLED
#endif // regular enable
#endif // ioexp emable
#endif // DEBUG
// record lifetime keystrokes in eeprom.
// because this updates the eeprom daily, 100,000 writes will last 273 years.
// five updates a day during periods of activity would only reduce the lifespan to 54 years. probably longer than i've got left
// a specific override key may also write the eeprom immediately
#define LIFETIME_KEYSTROKES
// wpm over last 60s. no storage or stats
#define WPM
// comment out to disable keyboard actions. keyboard header still necessary for various key definitions
#define REAL_KEYBOARD
// max matrixes to include
#ifdef REGULAR
const short MATRIX_COUNT = 4;
#else
const short MATRIX_COUNT = 1;
#endif // REGULAR
// current firmware version
const char* VERSION = "1.2.0.7";
#ifdef WATCHDOG_ENABLED
#include <avr/wdt.h>
#endif
#include <Keyboard.h>
// shared debug code
#ifdef DEBUG
char* debugBuffer = new char[128];
void log(const __FlashStringHelper* fmt, ...) {
if (!fmt) return;
va_list argp;
va_start(argp, fmt);
vsnprintf_P(debugBuffer, 128, (PGM_P)fmt, argp);
va_end(argp);
if(Serial)Serial.println(debugBuffer);
}
// memory layout on this is a little more predictable
int freeMemory() {
char* heapStack = malloc(8);
int f = (int)&heapStack - (int)heapStack;
free(heapStack);
log(F("free: %d"), f);
return f;
}
#else
inline void log(const __FlashStringHelper* _, ...) {}
#endif
#include "matrix.h"
#include "macro.h"
#include "matrix_dactyl.h"
Matrix matricies[MATRIX_COUNT];
Overlay myOverlays[1];
const char* instructions = "Hold T and E at the same time to change between simple keyboard and key information mode.";
void setup() {
//Serial.begin(9600);
//while(!Serial);
#ifdef WATCHDOG_ENABLED
MCUSR = 0;
wdt_disable();
#endif // WATCHDOG_ENABLED
#ifdef IO_EXPANDER
//while(!Serial);
while (!ioexp.begin()) {
if(Serial)Serial.print(F("Could not init left deck (FW: "));
if(Serial)Serial.write(VERSION);
if(Serial)Serial.println(")");
delay(750);
}
#else
#ifdef WATCHDOG_ENABLED
delay(10000); // wait ten seconds instead
#endif // WATCHDOG_ENABLED
#endif // IO_EXPANDER
#ifdef REAL_KEYBOARD
Keyboard.begin();
#endif // REAL_KEYBOARD
//init_matrix();
init_test_matrix();
//init_overlay();
init_macros();
if(Serial)Serial.write(VERSION);
if(Serial)Serial.println(F(" startup complete."));
#ifdef LIFETIME_KEYSTROKES
EEPROM.get(0, keystrokes);
#endif // LIFETIME_KEYSTROKES
}
void init_test_matrix() {
matricies[0] = test_board_matrix();
for (int i = 0; i < MATRIX_COUNT; i++) {
Matrix* m = matricies + i;
configure_matrix(m);
}
}
void init_matrix() {
return;
matricies[M_RIGHT_MAIN] = main_matrix_right();
matricies[M_RIGHT_THUMB] = thumb_matrix_right();
matricies[M_LEFT_MAIN] = main_matrix_left();
matricies[M_LEFT_THUMB] = thumb_matrix_left();
for (int i = 0; i < MATRIX_COUNT; i++) {
Matrix* m = matricies + i;
configure_matrix(m);
}
}
void init_overlay() {
overlay_main(myOverlays);
overlays = myOverlays;
}
void init_macros() {
memset(macros, 0, sizeof(Macro)*MACRO_COUNT);
macros[0].seq = malloc(sizeof(char) * 22);
sprintf_P(macros[0].seq, PSTR("r35k%cdsre r2k%cdsre k%c"), KEY_F11, KEY_DOWN_ARROW, KEY_RETURN);
//lentest(macros);
macros[1].seq = malloc(sizeof(char) * 7);
sprintf_P(macros[1].seq, PSTR("h%ck%cu%c"), KEY_LEFT_ALT, KEY_F2, KEY_LEFT_ALT);
//lentest(macros+1);
}
#ifdef LOOPTIMER
unsigned long lastLoop = 0;
unsigned long lastReport = 0;
void idlecheck() {
unsigned long ms = millis();
if (ms - lastReport > 1000) {
lastReport = ms;
freeMemory();
log(F("loop: %d"), (ms - lastLoop));
}
lastLoop = ms;
}
#endif // LOOPTIMER
bool instruct = false;
void loop() {
#ifdef WATCHDOG_ENABLED
wdt_enable(WDTO_250MS); // col/row process shouldn't take longer than 250ms
#endif // WATCHDOG_ENABLED
for (short xi = 0; xi < MATRIX_COUNT; ++xi) {
process(matricies + xi, xi);
}
if (!instruct) {
delay(2000);
if(Serial)Serial.println(F("instructing"));
Keyboard.write(instructions, strlen(instructions));
instruct = true;
}
#ifdef LOOPTIMER
idlecheck();
#endif // LOOPTIMER
#ifdef LIFETIME_KEYSTROKES
savecheck();
#endif // LIFETIME_KEYSTROKES
#ifdef WPM
cpmproc();
#endif // WPM
}