summaryrefslogtreecommitdiff
path: root/users/bbaserdem/bbaserdem.c
blob: 08346c3d64fe098d4b5d436514173d4f54e7019d (plain)
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/* Copyright 2021 Batuhan Başerdem
 * <baserdem.batuhan@gmail.com> @bbaserdem
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "bbaserdem.h"
// Language imports
#include <sendstring_dvorak.h>
// Need memcpy and memcmp from string.h along with transfer stuff
#ifdef SPLIT_KEYBOARD
#include "transactions.h"
#include <string.h>
#endif // SPLIT_KEYBOARD

/*-------------------------*\
|*-----KEYBOARD CONFIG-----*|
\*-------------------------*/
userspace_config_t userspace_config;
userspace_runtime_t userspace_runtime;

/*---------------------------------*\
|*----SPLIT KEYBOARD TRANSPORT-----*|
\*---------------------------------*/
#ifdef SPLIT_KEYBOARD
userspace_config_t transport_userspace_config;
userspace_runtime_t transport_userspace_runtime;

// Translate the RPC data to the local variable
void userspace_config_sync(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
    // Copy incoming data to local variable
    if (in_buflen == sizeof(transport_userspace_config)) {
        memcpy(&transport_userspace_config, in_data, in_buflen);
    }
    // There is no data to send back; so no output handling
}
void userspace_runtime_sync(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
    // Copy incoming data to local variable
    if (in_buflen == sizeof(transport_userspace_runtime)) {
        memcpy(&transport_userspace_runtime, in_data, in_buflen);
    }
    // There is no data to send back; so no output handling
}

// Either send or receive the correct data
void userspace_transport_update(void) {
    if (is_keyboard_master()) {
        // If we are the main device; we want to send info.
        transport_userspace_config.raw = userspace_config.raw;
        transport_userspace_runtime.raw = userspace_runtime.raw;
    } else {
        // If we are the secondary device; we want to receive info, and save to eeprom.
        userspace_config.raw = transport_userspace_config.raw;
        userspace_runtime.raw = transport_userspace_runtime.raw;
    }
}

// Initiate the protocol on sync
void userspace_transport_sync(bool force_sync) {
    if (is_keyboard_master()) {
        // Keep track of the last state
        static userspace_config_t last_userspace_config;
        static userspace_runtime_t last_userspace_runtime;
        bool needs_sync = false;

        // Check if the config values are different
        if (memcmp(&transport_userspace_config, &last_userspace_config, sizeof(transport_userspace_config))) {
            needs_sync = true;
            memcpy(&last_userspace_config, &transport_userspace_config, sizeof(transport_userspace_config));
        }
        // Perform the sync if requested
        if (needs_sync || force_sync) {
            transaction_rpc_send(RPC_ID_CONFIG_SYNC, sizeof(transport_userspace_config), &transport_userspace_config);
            needs_sync = false;
        }

        // Check if the runtime values are different
        if (memcmp(&transport_userspace_runtime, &last_userspace_runtime, sizeof(transport_userspace_runtime))) {
            needs_sync = true;
            memcpy(&last_userspace_runtime, &transport_userspace_runtime, sizeof(transport_userspace_runtime));
        }

        // Perform the sync if requested
        if (needs_sync || force_sync) {
            transaction_rpc_send(RPC_ID_RUNTIME_SYNC, sizeof(transport_userspace_runtime), &transport_userspace_runtime);
            needs_sync = false;
        }
    }
}
#endif // SPLIT_KEYBOARD

/*---------------------------*\
|*-----KEYBOARD PRE INIT-----*|
\*---------------------------*/
/* This code runs before anything is started.
 * Good for early hardware setup
 */
__attribute__ ((weak)) void keyboard_pre_init_keymap(void) {}
__attribute__ ((weak)) void keyboard_pre_init_user(void) {
    // Keymap specific stuff
    keyboard_pre_init_keymap();
}

/*---------------------*\
|*-----MATRIX INIT-----*|
\*---------------------*/
/* This code runs once midway thru the firmware process.
 * So far, sets the base layer and fixes unicode mode
 */
__attribute__ ((weak)) void matrix_init_keymap(void) {}
void matrix_init_user (void) {
    // Keymap specific things
    matrix_init_keymap();
}

/*----------------------------*\
|*-----KEYBOARD POST INIT-----*|
\*----------------------------*/
/* This code runs after anything is started.
 * Good for late hardware setup, like setting up layer specifications
 */
__attribute__ ((weak)) void keyboard_post_init_keymap(void) {}
__attribute__ ((weak)) void keyboard_post_init_user(void) {
    // Fix beginning base layer, in case some other firmware was flashed
    //  set_single_persistent_default_layer(_BASE);

    // Unicode mode
#   ifdef UNICODEMAP_ENABLE
    set_unicode_input_mode(UC_LNX);
#   endif // UNICODEMAP_ENABLE

    // Split keyboard halves communication
#   ifdef SPLIT_KEYBOARD
    // Register the transactions
    transaction_register_rpc( RPC_ID_CONFIG_SYNC, userspace_config_sync );
    transaction_register_rpc(RPC_ID_RUNTIME_SYNC, userspace_runtime_sync);
    // Load default config values
    if (is_keyboard_master()) { 
        // If we are main; load from eeconfig
        userspace_config.raw = eeconfig_read_user();
        // And update the transport variable
        userspace_transport_update();
        // Do one forced transfer to sync halves
        userspace_transport_sync(true);
    } else {
        // Just sync the data received
        userspace_transport_update();
    }
#   else // SPLIT_KEYBOARD
    // If we are not split; just load from eeprom
    userspace_config.raw = eeconfig_read_user();
#   endif // SPLIT_KEYBOARD

    // Backlight LED
#   ifdef BACKLIGHT_ENABLE
    keyboard_post_init_backlight();
#   endif // BACKLIGHT_ENABLE

    // RGB underglow
#   ifdef RGBLIGHT_ENABLE
    keyboard_post_init_underglow();
#   endif // RGBLIGHT_ENABLE

    // Keymap specific stuff
    keyboard_post_init_keymap();
}

/*---------------------------*\
|*-----HOUSEKEEPING TASK-----*|
\*---------------------------*/
/* I have no idea what this does
 */
__attribute__ ((weak)) void housekeeping_task_keymap(void) {}
void housekeeping_task_user(void) {
    // Check eeprom every now and then
    static userspace_config_t prev_userspace_config;
    static fast_timer_t throttle_timer = 0;
    static bool init_flag = true;

    // Read this if we never read it before
    if (init_flag) {
        init_flag = false;
        prev_userspace_config.raw = eeconfig_read_user();
    }

    // Throttled tasks here
    if (timer_elapsed_fast(throttle_timer) >= HOUSEKEEPING_THROTTLE_INTERVAL_MS) {
        // Refresh timer
        throttle_timer = timer_read_fast();
        // Check userspace config for eeprom updates
        if (memcmp(&prev_userspace_config, &userspace_config, sizeof(userspace_config))) {
            memcpy(&prev_userspace_config, &userspace_config, sizeof(userspace_config));
            eeconfig_update_user(userspace_config.raw);
        }
    }

    // Do transport stuff
#   ifdef SPLIT_KEYBOARD
    userspace_transport_update();
    userspace_transport_sync(false);
#   endif // SPLIT_KEYBOARD

    // Hook to keymap code
    housekeeping_task_keymap();
}

/*-----------------------*\
|*-----EECONFIG INIT-----*|
\*-----------------------*/
/* Default values to send to the eeprom
 */
void eeconfig_init_user(void) {
    // Set everything to default
    userspace_config.raw = 0;
    // Set encoder states to sane defaults if enabled
#   ifdef ENCODER_ENABLE
    reset_encoder_state();
#   endif // ENCODER_ENABLE
}

/*------------------------*\
|*-----PROCESS RECORD-----*|
\*------------------------*/
/* Process record: custom keycodes to process here
 * Allow also the following codes to hook here as well;
 *  Macro definitions
 *  Audio hooks
 */
__attribute__ ((weak))
bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
    return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    // Return after running through all individual hooks
    return
        process_record_keymap(keycode, record)  &&
#       ifdef AUDIO_ENABLE
        process_record_audio(keycode, record)   &&
#       endif // AUDIO_ENABLE
#       ifdef ENCODER_ENABLE
        process_record_encoder(keycode, record) &&
#       endif // ENCODER_ENABLE
        process_record_macro(keycode, record);
}

/*---------------------*\
|*-----MATRIX SCAN-----*|
\*---------------------*/
/* This code runs every frame
 * I used to check for layer switching here, but layer state is better used.
 * Try to not put anything here; as it runs hundreds time per second-ish
 */
__attribute__ ((weak)) void matrix_scan_keymap(void) { }
void matrix_scan_user (void) {
    // Keymap specific scan function
    matrix_scan_keymap();
}

/*---------------------*\
|*-----LAYER STATE-----*|
\*---------------------*/
/* This code runs after every layer change
 * State represents the new layer state.
 */
__attribute__ ((weak))
layer_state_t layer_state_set_keymap (layer_state_t state) {
    return state;
}
layer_state_t layer_state_set_user(layer_state_t state) {
    // Keymap layer state setting
    state = layer_state_set_keymap(state);
    // For underglow stuff
#   ifdef RGBLIGHT_ENABLE
    state = layer_state_set_underglow(state);
#   endif // RGBLIGHT_ENABLE
    // Audio playback
#   ifdef AUDIO_ENABLE
    state = layer_state_set_audio(state);
#   endif // AUDIO_ENABLE

    return state;
}

/*-----------------------------*\
|*-----DEFAULT LAYER STATE-----*|
\*-----------------------------*/
/* This code runs after every time default base layer is changed
 */
__attribute__ ((weak))
layer_state_t default_layer_state_set_keymap (layer_state_t state) {
    return state;
}
layer_state_t default_layer_state_set_user(layer_state_t state) {
    // Keymap level code
    state = default_layer_state_set_keymap(state);
    return state;
}

/*------------------------*\
|*-----LED SET KEYMAP-----*|
\*------------------------*/
/* Code for LED indicators
 * I'm not sure when exactly does this code run
 */
__attribute__ ((weak)) void led_set_keymap(uint8_t usb_led) {}
void led_set_user(uint8_t usb_led) {
    led_set_keymap(usb_led);
}

/*-----------------*\
|*-----SUSPEND-----*|
\*-----------------*/
/* Suspend stuff here, mostly for the rgb lighting. 
 */
__attribute__ ((weak)) void suspend_power_down_keymap (void) { }
void suspend_power_down_user(void) {
    suspend_power_down_keymap();
    // RGB matrix sleep hook
#   ifdef RGB_MATRIX_ENABLE
    suspend_power_down_rgb();
#   endif // RGB_MATRIX_ENABLE
}
__attribute__ ((weak)) void suspend_wakeup_init_keymap (void) { }
void suspend_wakeup_init_user(void) {
    suspend_wakeup_init_keymap();
    // RGB matrix sleep hook
#   ifdef RGB_MATRIX_ENABLE
    suspend_wakeup_init_rgb();
#   endif // RGB_MATRIX_ENABLE
}

/*------------------*\
|*-----SHUTDOWN-----*|
\*------------------*/
/* Shutdown stuff here; for when entering bootmode.
 */
__attribute__ ((weak)) void shutdown_keymap (void) { }
void shutdown_user(void) {
    // Underglow LED hook on boot
#   ifdef RGBLIGHT_ENABLE
    shutdown_underglow();
#   endif // RGBLIGHT_ENABLE
    // Perkey led hook on boot
#   ifdef RGB_MATRIX_ENABLE
    shutdown_rgb();
#   endif // RGB_MATRIX_ENABLE
    // Keymap hooks
    shutdown_keymap();
}